blob: b3a7f387da329756403d001a421f0f659403c827 [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
1393 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001394 bool changed = false;
1395
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001396 /* Setting limited discoverable when powered off is
1397 * not a valid operation since it requires a timeout
1398 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1399 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001400 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001401 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001402 changed = true;
1403 }
1404
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001405 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001406 if (err < 0)
1407 goto failed;
1408
1409 if (changed)
1410 err = new_settings(hdev, sk);
1411
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001412 goto failed;
1413 }
1414
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001415 /* If the current mode is the same, then just update the timeout
1416 * value with the new value. And if only the timeout gets updated,
1417 * then no need for any HCI transactions.
1418 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001419 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1420 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1421 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001422 cancel_delayed_work(&hdev->discov_off);
1423 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001424
Marcel Holtmann36261542013-10-15 08:28:51 -07001425 if (cp->val && hdev->discov_timeout > 0) {
1426 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001427 queue_delayed_work(hdev->req_workqueue,
1428 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001429 }
1430
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001431 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001432 goto failed;
1433 }
1434
1435 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1436 if (!cmd) {
1437 err = -ENOMEM;
1438 goto failed;
1439 }
1440
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001441 /* Cancel any potential discoverable timeout that might be
1442 * still active and store new timeout value. The arming of
1443 * the timeout happens in the complete handler.
1444 */
1445 cancel_delayed_work(&hdev->discov_off);
1446 hdev->discov_timeout = timeout;
1447
Johan Hedbergaed1a882015-11-22 17:24:44 +03001448 if (cp->val)
1449 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1450 else
1451 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1452
Johan Hedbergb456f872013-10-19 23:38:22 +03001453 /* Limited discoverable mode */
1454 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001455 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001456 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001457 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001458
Johan Hedbergaed1a882015-11-22 17:24:44 +03001459 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1460 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001461
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001462failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001463 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001464 return err;
1465}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001466
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001467void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001468{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001469 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001470
1471 BT_DBG("status 0x%02x", status);
1472
1473 hci_dev_lock(hdev);
1474
Johan Hedberg333ae952015-03-17 13:48:47 +02001475 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001476 if (!cmd)
1477 goto unlock;
1478
Johan Hedberg37438c12013-10-14 16:20:05 +03001479 if (status) {
1480 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001481 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001482 goto remove_cmd;
1483 }
1484
Johan Hedberg2b76f452013-03-15 17:07:04 -05001485 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001486 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001487
Johan Hedberg37438c12013-10-14 16:20:05 +03001488remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001489 mgmt_pending_remove(cmd);
1490
1491unlock:
1492 hci_dev_unlock(hdev);
1493}
1494
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001495static int set_connectable_update_settings(struct hci_dev *hdev,
1496 struct sock *sk, u8 val)
1497{
1498 bool changed = false;
1499 int err;
1500
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001501 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001502 changed = true;
1503
1504 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001505 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001506 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001507 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1508 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001509 }
1510
1511 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1512 if (err < 0)
1513 return err;
1514
Johan Hedberg562064e2014-07-08 16:35:34 +03001515 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001516 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001517 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001518 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001519 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001520
1521 return 0;
1522}
1523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001524static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001525 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001526{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001527 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001528 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001529 int err;
1530
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001531 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001532
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001533 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1534 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001535 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1536 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001537
Johan Hedberga7e80f22013-01-09 16:05:19 +02001538 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001539 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1540 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001541
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001542 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001543
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001544 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001545 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001546 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001547 }
1548
Johan Hedberg333ae952015-03-17 13:48:47 +02001549 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1550 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001551 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1552 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001553 goto failed;
1554 }
1555
Johan Hedberg73f22f62010-12-29 16:00:25 +02001556 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1557 if (!cmd) {
1558 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001559 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001560 }
1561
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001562 if (cp->val) {
1563 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1564 } else {
1565 if (hdev->discov_timeout > 0)
1566 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001567
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001568 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1569 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1570 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001571 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001572
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001573 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1574 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001575
1576failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001578 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001579}
1580
Johan Hedbergb2939472014-07-30 09:22:23 +03001581static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001582 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001583{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001584 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001585 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001586 int err;
1587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001588 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001589
Johan Hedberga7e80f22013-01-09 16:05:19 +02001590 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001591 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1592 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001593
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001594 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001595
1596 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001597 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001598 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001599 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001600
Johan Hedbergb2939472014-07-30 09:22:23 +03001601 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001602 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001603 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001604
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001605 if (changed) {
1606 /* In limited privacy mode the change of bondable mode
1607 * may affect the local advertising address.
1608 */
1609 if (hdev_is_powered(hdev) &&
1610 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1611 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1612 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1613 queue_work(hdev->req_workqueue,
1614 &hdev->discoverable_update);
1615
Marcel Holtmann55594352013-10-06 16:11:57 -07001616 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001617 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001618
Marcel Holtmann55594352013-10-06 16:11:57 -07001619unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001620 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001621 return err;
1622}
1623
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001624static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1625 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001626{
1627 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001628 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001629 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001630 int err;
1631
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001632 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001633
Johan Hedberge6fe7982013-10-02 15:45:22 +03001634 status = mgmt_bredr_support(hdev);
1635 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001636 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1637 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001638
Johan Hedberga7e80f22013-01-09 16:05:19 +02001639 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001640 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1641 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001642
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001643 hci_dev_lock(hdev);
1644
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001645 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001646 bool changed = false;
1647
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001648 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001649 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001650 changed = true;
1651 }
1652
1653 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1654 if (err < 0)
1655 goto failed;
1656
1657 if (changed)
1658 err = new_settings(hdev, sk);
1659
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001660 goto failed;
1661 }
1662
Johan Hedberg333ae952015-03-17 13:48:47 +02001663 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001664 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1665 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001666 goto failed;
1667 }
1668
1669 val = !!cp->val;
1670
1671 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1672 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1673 goto failed;
1674 }
1675
1676 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1677 if (!cmd) {
1678 err = -ENOMEM;
1679 goto failed;
1680 }
1681
1682 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1683 if (err < 0) {
1684 mgmt_pending_remove(cmd);
1685 goto failed;
1686 }
1687
1688failed:
1689 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001690 return err;
1691}
1692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001693static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001694{
1695 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001696 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001697 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001698 int err;
1699
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001700 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001701
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001702 status = mgmt_bredr_support(hdev);
1703 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001704 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001705
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001706 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1708 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001709
Johan Hedberga7e80f22013-01-09 16:05:19 +02001710 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001711 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1712 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001713
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001714 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001715
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001716 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001717 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001718
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001719 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001720 changed = !hci_dev_test_and_set_flag(hdev,
1721 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001722 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001723 changed = hci_dev_test_and_clear_flag(hdev,
1724 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001725 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001726 changed = hci_dev_test_and_clear_flag(hdev,
1727 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001728 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001729 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001730 }
1731
1732 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1733 if (err < 0)
1734 goto failed;
1735
1736 if (changed)
1737 err = new_settings(hdev, sk);
1738
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001739 goto failed;
1740 }
1741
Johan Hedberg333ae952015-03-17 13:48:47 +02001742 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001743 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1744 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001745 goto failed;
1746 }
1747
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001748 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001749 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1750 goto failed;
1751 }
1752
1753 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1754 if (!cmd) {
1755 err = -ENOMEM;
1756 goto failed;
1757 }
1758
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001759 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001760 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1761 sizeof(cp->val), &cp->val);
1762
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001763 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001764 if (err < 0) {
1765 mgmt_pending_remove(cmd);
1766 goto failed;
1767 }
1768
1769failed:
1770 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001771 return err;
1772}
1773
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001774static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001775{
1776 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001777 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001778 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001779 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001781 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001782
Johan Hedberge6fe7982013-10-02 15:45:22 +03001783 status = mgmt_bredr_support(hdev);
1784 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001785 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001786
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001787 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001788 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1789 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001790
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001791 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001792 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1793 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001794
Johan Hedberga7e80f22013-01-09 16:05:19 +02001795 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001796 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1797 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001798
Marcel Holtmannee392692013-10-01 22:59:23 -07001799 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001800
Johan Hedberg333ae952015-03-17 13:48:47 +02001801 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001802 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1803 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001804 goto unlock;
1805 }
1806
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001807 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001808 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001809 } else {
1810 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001811 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1812 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001813 goto unlock;
1814 }
1815
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001816 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001817 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001818
1819 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1820 if (err < 0)
1821 goto unlock;
1822
1823 if (changed)
1824 err = new_settings(hdev, sk);
1825
1826unlock:
1827 hci_dev_unlock(hdev);
1828 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001829}
1830
Marcel Holtmann1904a852015-01-11 13:50:44 -08001831static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001832{
1833 struct cmd_lookup match = { NULL, hdev };
1834
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301835 hci_dev_lock(hdev);
1836
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001837 if (status) {
1838 u8 mgmt_err = mgmt_status(status);
1839
1840 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1841 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301842 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001843 }
1844
1845 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1846
1847 new_settings(hdev, match.sk);
1848
1849 if (match.sk)
1850 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001851
1852 /* Make sure the controller has a good default for
1853 * advertising data. Restrict the update to when LE
1854 * has actually been enabled. During power on, the
1855 * update in powered_update_hci will take care of it.
1856 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001857 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001858 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001859 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301860 if (ext_adv_capable(hdev)) {
1861 int err;
1862
1863 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1864 if (!err)
1865 __hci_req_update_scan_rsp_data(&req, 0x00);
1866 } else {
1867 __hci_req_update_adv_data(&req, 0x00);
1868 __hci_req_update_scan_rsp_data(&req, 0x00);
1869 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001870 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001871 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001872 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301873
1874unlock:
1875 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001876}
1877
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001878static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001879{
1880 struct mgmt_mode *cp = data;
1881 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001882 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001883 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001884 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001885 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001887 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001888
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001889 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001890 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1891 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001892
Johan Hedberga7e80f22013-01-09 16:05:19 +02001893 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001894 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1895 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001896
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001897 /* Bluetooth single mode LE only controllers or dual-mode
1898 * controllers configured as LE only devices, do not allow
1899 * switching LE off. These have either LE enabled explicitly
1900 * or BR/EDR has been previously switched off.
1901 *
1902 * When trying to enable an already enabled LE, then gracefully
1903 * send a positive response. Trying to disable it however will
1904 * result into rejection.
1905 */
1906 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1907 if (cp->val == 0x01)
1908 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1909
Johan Hedberga69e8372015-03-06 21:08:53 +02001910 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1911 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001912 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001913
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001914 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001915
1916 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001917 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001918
Florian Grandel847818d2015-06-18 03:16:46 +02001919 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001920 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001921
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001922 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001923 bool changed = false;
1924
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001925 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001926 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001927 changed = true;
1928 }
1929
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001930 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001931 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001932 changed = true;
1933 }
1934
Johan Hedberg06199cf2012-02-22 16:37:11 +02001935 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1936 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001937 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001938
1939 if (changed)
1940 err = new_settings(hdev, sk);
1941
Johan Hedberg1de028c2012-02-29 19:55:35 -08001942 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001943 }
1944
Johan Hedberg333ae952015-03-17 13:48:47 +02001945 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1946 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001947 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1948 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001949 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001950 }
1951
1952 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1953 if (!cmd) {
1954 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001955 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001956 }
1957
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001958 hci_req_init(&req, hdev);
1959
Johan Hedberg06199cf2012-02-22 16:37:11 +02001960 memset(&hci_cp, 0, sizeof(hci_cp));
1961
1962 if (val) {
1963 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001964 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001965 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001966 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001967 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301968
1969 if (ext_adv_capable(hdev))
1970 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001971 }
1972
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001973 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1974 &hci_cp);
1975
1976 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301977 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001978 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001979
Johan Hedberg1de028c2012-02-29 19:55:35 -08001980unlock:
1981 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001982 return err;
1983}
1984
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001985/* This is a helper function to test for pending mgmt commands that can
1986 * cause CoD or EIR HCI commands. We can only allow one such pending
1987 * mgmt command at a time since otherwise we cannot easily track what
1988 * the current values are, will be, and based on that calculate if a new
1989 * HCI command needs to be sent and if yes with what value.
1990 */
1991static bool pending_eir_or_class(struct hci_dev *hdev)
1992{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001993 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001994
1995 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1996 switch (cmd->opcode) {
1997 case MGMT_OP_ADD_UUID:
1998 case MGMT_OP_REMOVE_UUID:
1999 case MGMT_OP_SET_DEV_CLASS:
2000 case MGMT_OP_SET_POWERED:
2001 return true;
2002 }
2003 }
2004
2005 return false;
2006}
2007
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002008static const u8 bluetooth_base_uuid[] = {
2009 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2010 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2011};
2012
2013static u8 get_uuid_size(const u8 *uuid)
2014{
2015 u32 val;
2016
2017 if (memcmp(uuid, bluetooth_base_uuid, 12))
2018 return 128;
2019
2020 val = get_unaligned_le32(&uuid[12]);
2021 if (val > 0xffff)
2022 return 32;
2023
2024 return 16;
2025}
2026
Johan Hedberg92da6092013-03-15 17:06:55 -05002027static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2028{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002029 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002030
2031 hci_dev_lock(hdev);
2032
Johan Hedberg333ae952015-03-17 13:48:47 +02002033 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002034 if (!cmd)
2035 goto unlock;
2036
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002037 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2038 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002039
2040 mgmt_pending_remove(cmd);
2041
2042unlock:
2043 hci_dev_unlock(hdev);
2044}
2045
Marcel Holtmann1904a852015-01-11 13:50:44 -08002046static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002047{
2048 BT_DBG("status 0x%02x", status);
2049
2050 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2051}
2052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002055 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002056 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002057 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002058 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002059 int err;
2060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002061 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002062
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002063 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002064
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002065 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002066 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2067 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002068 goto failed;
2069 }
2070
Andre Guedes92c4c202012-06-07 19:05:44 -03002071 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002072 if (!uuid) {
2073 err = -ENOMEM;
2074 goto failed;
2075 }
2076
2077 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002078 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002079 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002080
Johan Hedbergde66aa62013-01-27 00:31:27 +02002081 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002082
Johan Hedberg890ea892013-03-15 17:06:52 -05002083 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002084
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002085 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002086 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002087
Johan Hedberg92da6092013-03-15 17:06:55 -05002088 err = hci_req_run(&req, add_uuid_complete);
2089 if (err < 0) {
2090 if (err != -ENODATA)
2091 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002092
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002093 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2094 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002095 goto failed;
2096 }
2097
2098 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002099 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002100 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002101 goto failed;
2102 }
2103
2104 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002105
2106failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002107 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002108 return err;
2109}
2110
Johan Hedberg24b78d02012-02-23 23:24:30 +02002111static bool enable_service_cache(struct hci_dev *hdev)
2112{
2113 if (!hdev_is_powered(hdev))
2114 return false;
2115
Marcel Holtmann238be782015-03-13 02:11:06 -07002116 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002117 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2118 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002119 return true;
2120 }
2121
2122 return false;
2123}
2124
Marcel Holtmann1904a852015-01-11 13:50:44 -08002125static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002126{
2127 BT_DBG("status 0x%02x", status);
2128
2129 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2130}
2131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002132static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002133 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002134{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002135 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002136 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002137 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002138 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 -05002139 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002140 int err, found;
2141
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002142 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002144 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002145
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002146 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002147 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2148 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002149 goto unlock;
2150 }
2151
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002152 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002153 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002154
Johan Hedberg24b78d02012-02-23 23:24:30 +02002155 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002156 err = mgmt_cmd_complete(sk, hdev->id,
2157 MGMT_OP_REMOVE_UUID,
2158 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002159 goto unlock;
2160 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002161
Johan Hedberg9246a862012-02-23 21:33:16 +02002162 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002163 }
2164
2165 found = 0;
2166
Johan Hedberg056341c2013-01-27 00:31:30 +02002167 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002168 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2169 continue;
2170
2171 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002172 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002173 found++;
2174 }
2175
2176 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002177 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2178 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002179 goto unlock;
2180 }
2181
Johan Hedberg9246a862012-02-23 21:33:16 +02002182update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002183 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002184
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002185 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002186 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002187
Johan Hedberg92da6092013-03-15 17:06:55 -05002188 err = hci_req_run(&req, remove_uuid_complete);
2189 if (err < 0) {
2190 if (err != -ENODATA)
2191 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002192
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002193 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2194 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002195 goto unlock;
2196 }
2197
2198 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002199 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002200 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002201 goto unlock;
2202 }
2203
2204 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002205
2206unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002208 return err;
2209}
2210
Marcel Holtmann1904a852015-01-11 13:50:44 -08002211static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002212{
2213 BT_DBG("status 0x%02x", status);
2214
2215 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2216}
2217
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002218static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002219 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002220{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002221 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002222 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002223 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002224 int err;
2225
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002226 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002227
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002228 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002229 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2230 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002231
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002232 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002233
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002234 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002235 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2236 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002237 goto unlock;
2238 }
2239
2240 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002241 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2242 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002243 goto unlock;
2244 }
2245
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002246 hdev->major_class = cp->major;
2247 hdev->minor_class = cp->minor;
2248
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002249 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002250 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2251 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002252 goto unlock;
2253 }
2254
Johan Hedberg890ea892013-03-15 17:06:52 -05002255 hci_req_init(&req, hdev);
2256
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002257 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002258 hci_dev_unlock(hdev);
2259 cancel_delayed_work_sync(&hdev->service_cache);
2260 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002261 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002262 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002263
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002264 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002265
Johan Hedberg92da6092013-03-15 17:06:55 -05002266 err = hci_req_run(&req, set_class_complete);
2267 if (err < 0) {
2268 if (err != -ENODATA)
2269 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002270
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002271 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2272 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002273 goto unlock;
2274 }
2275
2276 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002277 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002278 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002279 goto unlock;
2280 }
2281
2282 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002283
Johan Hedbergb5235a62012-02-21 14:32:24 +02002284unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002285 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002286 return err;
2287}
2288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002290 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002291{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002292 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002293 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2294 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002295 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002296 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002297 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002298
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002299 BT_DBG("request for %s", hdev->name);
2300
2301 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002302 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2303 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002304
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002305 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002306 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002307 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2308 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002309 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2310 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002311 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002312
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002313 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002314 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002315 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2316 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002317 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2318 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002319 }
2320
Johan Hedberg4ae143012013-01-20 14:27:13 +02002321 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002322 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2323 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002324
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002325 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002326 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002327
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002328 for (i = 0; i < key_count; i++) {
2329 struct mgmt_link_key_info *key = &cp->keys[i];
2330
Marcel Holtmann8e991132014-01-10 02:07:25 -08002331 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002332 return mgmt_cmd_status(sk, hdev->id,
2333 MGMT_OP_LOAD_LINK_KEYS,
2334 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002335 }
2336
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002337 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002338
2339 hci_link_keys_clear(hdev);
2340
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002342 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002343 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002344 changed = hci_dev_test_and_clear_flag(hdev,
2345 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002346
2347 if (changed)
2348 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002349
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002350 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002351 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002352
Alain Michaud600a8742020-01-07 00:43:17 +00002353 if (hci_is_blocked_key(hdev,
2354 HCI_BLOCKED_KEY_TYPE_LINKKEY,
2355 key->val)) {
2356 bt_dev_warn(hdev, "Skipping blocked link key for %pMR",
2357 &key->addr.bdaddr);
2358 continue;
2359 }
2360
Johan Hedberg58e92932014-06-24 14:00:26 +03002361 /* Always ignore debug keys and require a new pairing if
2362 * the user wants to use them.
2363 */
2364 if (key->type == HCI_LK_DEBUG_COMBINATION)
2365 continue;
2366
Johan Hedberg7652ff62014-06-24 13:15:49 +03002367 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2368 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002369 }
2370
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002371 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002372
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002373 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002374
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002375 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376}
2377
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002378static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002379 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002380{
2381 struct mgmt_ev_device_unpaired ev;
2382
2383 bacpy(&ev.addr.bdaddr, bdaddr);
2384 ev.addr.type = addr_type;
2385
2386 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002387 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002388}
2389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002390static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002391 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002392{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002393 struct mgmt_cp_unpair_device *cp = data;
2394 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002395 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002396 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002397 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002398 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002399 int err;
2400
Johan Hedberga8a1d192011-11-10 15:54:38 +02002401 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002402 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2403 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002404
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002405 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002406 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2407 MGMT_STATUS_INVALID_PARAMS,
2408 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002409
Johan Hedberg118da702013-01-20 14:27:20 +02002410 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002411 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2412 MGMT_STATUS_INVALID_PARAMS,
2413 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002414
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002415 hci_dev_lock(hdev);
2416
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002417 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002418 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2419 MGMT_STATUS_NOT_POWERED, &rp,
2420 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002421 goto unlock;
2422 }
2423
Johan Hedberge0b2b272014-02-18 17:14:31 +02002424 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002425 /* If disconnection is requested, then look up the
2426 * connection. If the remote device is connected, it
2427 * will be later used to terminate the link.
2428 *
2429 * Setting it to NULL explicitly will cause no
2430 * termination of the link.
2431 */
2432 if (cp->disconnect)
2433 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2434 &cp->addr.bdaddr);
2435 else
2436 conn = NULL;
2437
Johan Hedberg124f6e32012-02-09 13:50:12 +02002438 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002439 if (err < 0) {
2440 err = mgmt_cmd_complete(sk, hdev->id,
2441 MGMT_OP_UNPAIR_DEVICE,
2442 MGMT_STATUS_NOT_PAIRED, &rp,
2443 sizeof(rp));
2444 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002445 }
2446
Johan Hedbergec182f02015-10-21 18:03:03 +03002447 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002448 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002449
Johan Hedbergec182f02015-10-21 18:03:03 +03002450 /* LE address type */
2451 addr_type = le_addr_type(cp->addr.type);
2452
Matias Karhumaacb28c302018-09-26 09:13:46 +03002453 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2454 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002455 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002456 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2457 MGMT_STATUS_NOT_PAIRED, &rp,
2458 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002459 goto unlock;
2460 }
2461
Johan Hedbergec182f02015-10-21 18:03:03 +03002462 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2463 if (!conn) {
2464 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2465 goto done;
2466 }
2467
Johan Hedbergc81d5552015-10-22 09:38:35 +03002468
Johan Hedbergec182f02015-10-21 18:03:03 +03002469 /* Defer clearing up the connection parameters until closing to
2470 * give a chance of keeping them if a repairing happens.
2471 */
2472 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2473
Johan Hedbergfc643612015-10-22 09:38:31 +03002474 /* Disable auto-connection parameters if present */
2475 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2476 if (params) {
2477 if (params->explicit_connect)
2478 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2479 else
2480 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2481 }
2482
Johan Hedbergec182f02015-10-21 18:03:03 +03002483 /* If disconnection is not requested, then clear the connection
2484 * variable so that the link is not terminated.
2485 */
2486 if (!cp->disconnect)
2487 conn = NULL;
2488
2489done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002490 /* If the connection variable is set, then termination of the
2491 * link is requested.
2492 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002493 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002494 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2495 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002496 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002497 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002498 }
2499
Johan Hedberg124f6e32012-02-09 13:50:12 +02002500 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002501 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002502 if (!cmd) {
2503 err = -ENOMEM;
2504 goto unlock;
2505 }
2506
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002507 cmd->cmd_complete = addr_cmd_complete;
2508
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002509 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002510 if (err < 0)
2511 mgmt_pending_remove(cmd);
2512
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002513unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002514 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002515 return err;
2516}
2517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002518static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002519 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002520{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002521 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002522 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002523 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002524 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002525 int err;
2526
2527 BT_DBG("");
2528
Johan Hedberg06a63b12013-01-20 14:27:21 +02002529 memset(&rp, 0, sizeof(rp));
2530 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2531 rp.addr.type = cp->addr.type;
2532
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002533 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002534 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2535 MGMT_STATUS_INVALID_PARAMS,
2536 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002539
2540 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002541 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2542 MGMT_STATUS_NOT_POWERED, &rp,
2543 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002544 goto failed;
2545 }
2546
Johan Hedberg333ae952015-03-17 13:48:47 +02002547 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002548 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2549 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002550 goto failed;
2551 }
2552
Andre Guedes591f47f2012-04-24 21:02:49 -03002553 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002554 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2555 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002556 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002557 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2558 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002559
Vishal Agarwalf9607272012-06-13 05:32:43 +05302560 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002561 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2562 MGMT_STATUS_NOT_CONNECTED, &rp,
2563 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002564 goto failed;
2565 }
2566
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002567 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002568 if (!cmd) {
2569 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002570 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002571 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002572
Johan Hedbergf5818c22014-12-05 13:36:02 +02002573 cmd->cmd_complete = generic_cmd_complete;
2574
Johan Hedberge3f2f922014-08-18 20:33:33 +03002575 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002576 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002577 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002578
2579failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002580 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002581 return err;
2582}
2583
Andre Guedes57c14772012-04-24 21:02:50 -03002584static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002585{
2586 switch (link_type) {
2587 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002588 switch (addr_type) {
2589 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002590 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002591
Johan Hedberg48264f02011-11-09 13:58:58 +02002592 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002593 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002594 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002595 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002596
Johan Hedberg4c659c32011-11-07 23:13:39 +02002597 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002598 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002599 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002600 }
2601}
2602
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002603static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2604 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002605{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002606 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002607 struct hci_conn *c;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002608 int err;
2609 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002610
2611 BT_DBG("");
2612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002613 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002614
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002615 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002616 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2617 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002618 goto unlock;
2619 }
2620
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002621 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002622 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2623 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002624 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002625 }
2626
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002627 rp = kmalloc(struct_size(rp, addr, i), GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002628 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002629 err = -ENOMEM;
2630 goto unlock;
2631 }
2632
Johan Hedberg2784eb42011-01-21 13:56:35 +02002633 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002634 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002635 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2636 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002637 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002638 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002639 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002640 continue;
2641 i++;
2642 }
2643
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002644 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002645
Johan Hedberg4c659c32011-11-07 23:13:39 +02002646 /* Recalculate length in case of filtered SCO connections, etc */
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002647 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo A. R. Silva72bb1692019-08-29 20:12:11 -05002648 struct_size(rp, addr, i));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002649
Johan Hedberga38528f2011-01-22 06:46:43 +02002650 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002651
2652unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002653 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002654 return err;
2655}
2656
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002657static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002658 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002659{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002660 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002661 int err;
2662
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002663 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002664 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002665 if (!cmd)
2666 return -ENOMEM;
2667
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002668 cmd->cmd_complete = addr_cmd_complete;
2669
Johan Hedbergd8457692012-02-17 14:24:57 +02002670 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002671 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002672 if (err < 0)
2673 mgmt_pending_remove(cmd);
2674
2675 return err;
2676}
2677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002678static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002679 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002680{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002681 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002682 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002683 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002684 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002685 int err;
2686
2687 BT_DBG("");
2688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002689 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002690
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002691 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002692 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2693 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002694 goto failed;
2695 }
2696
Johan Hedbergd8457692012-02-17 14:24:57 +02002697 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002698 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002699 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2700 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002701 goto failed;
2702 }
2703
2704 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002705 struct mgmt_cp_pin_code_neg_reply ncp;
2706
2707 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002708
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002709 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002710
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002711 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002712 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002713 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2714 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002715
2716 goto failed;
2717 }
2718
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002719 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002720 if (!cmd) {
2721 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002722 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002723 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002724
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002725 cmd->cmd_complete = addr_cmd_complete;
2726
Johan Hedbergd8457692012-02-17 14:24:57 +02002727 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002729 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002730
2731 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2732 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002733 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002734
2735failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002736 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002737 return err;
2738}
2739
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002740static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2741 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002742{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002743 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002744
2745 BT_DBG("");
2746
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002747 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002748 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2749 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002750
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002751 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002752
2753 hdev->io_capability = cp->io_capability;
2754
2755 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002756 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002757
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002758 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002759
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002760 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2761 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002762}
2763
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002764static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002765{
2766 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002767 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002768
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002769 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002770 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2771 continue;
2772
Johan Hedberge9a416b2011-02-19 12:05:56 -03002773 if (cmd->user_data != conn)
2774 continue;
2775
2776 return cmd;
2777 }
2778
2779 return NULL;
2780}
2781
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002782static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002783{
2784 struct mgmt_rp_pair_device rp;
2785 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002786 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002787
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002788 bacpy(&rp.addr.bdaddr, &conn->dst);
2789 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002790
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002791 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2792 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793
2794 /* So we don't get further callbacks for this connection */
2795 conn->connect_cfm_cb = NULL;
2796 conn->security_cfm_cb = NULL;
2797 conn->disconn_cfm_cb = NULL;
2798
David Herrmann76a68ba2013-04-06 20:28:37 +02002799 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002800
2801 /* The device is paired so there is no need to remove
2802 * its connection parameters anymore.
2803 */
2804 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002805
2806 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002807
2808 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002809}
2810
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002811void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2812{
2813 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002814 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002815
2816 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002817 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002818 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002819 mgmt_pending_remove(cmd);
2820 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002821}
2822
Johan Hedberge9a416b2011-02-19 12:05:56 -03002823static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2824{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002825 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002826
2827 BT_DBG("status %u", status);
2828
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002829 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002830 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002831 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002832 return;
2833 }
2834
2835 cmd->cmd_complete(cmd, mgmt_status(status));
2836 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002837}
2838
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002839static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302840{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002841 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302842
2843 BT_DBG("status %u", status);
2844
2845 if (!status)
2846 return;
2847
2848 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002849 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302850 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002851 return;
2852 }
2853
2854 cmd->cmd_complete(cmd, mgmt_status(status));
2855 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302856}
2857
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002858static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002859 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002860{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002861 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002862 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002863 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002864 u8 sec_level, auth_type;
2865 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002866 int err;
2867
2868 BT_DBG("");
2869
Szymon Jancf950a30e2013-01-18 12:48:07 +01002870 memset(&rp, 0, sizeof(rp));
2871 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2872 rp.addr.type = cp->addr.type;
2873
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002874 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002875 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2876 MGMT_STATUS_INVALID_PARAMS,
2877 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002878
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002879 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002880 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2881 MGMT_STATUS_INVALID_PARAMS,
2882 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002883
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002884 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002885
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002886 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002887 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2888 MGMT_STATUS_NOT_POWERED, &rp,
2889 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002890 goto unlock;
2891 }
2892
Johan Hedberg55e76b32015-03-10 22:34:40 +02002893 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2894 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2895 MGMT_STATUS_ALREADY_PAIRED, &rp,
2896 sizeof(rp));
2897 goto unlock;
2898 }
2899
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002900 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002901 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002902
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002903 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002904 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2905 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002906 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002907 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002908 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002909
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002910 /* When pairing a new device, it is expected to remember
2911 * this device for future connections. Adding the connection
2912 * parameter information ahead of time allows tracking
2913 * of the slave preferred values and will speed up any
2914 * further connection establishment.
2915 *
2916 * If connection parameters already exist, then they
2917 * will be kept and this function does nothing.
2918 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002919 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2920
2921 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2922 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002923
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002924 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2925 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002926 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002927 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002928
Ville Tervo30e76272011-02-22 16:10:53 -03002929 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002930 int status;
2931
2932 if (PTR_ERR(conn) == -EBUSY)
2933 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002934 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2935 status = MGMT_STATUS_NOT_SUPPORTED;
2936 else if (PTR_ERR(conn) == -ECONNREFUSED)
2937 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002938 else
2939 status = MGMT_STATUS_CONNECT_FAILED;
2940
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002941 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2942 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002943 goto unlock;
2944 }
2945
2946 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002947 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002948 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2949 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002950 goto unlock;
2951 }
2952
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002953 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002954 if (!cmd) {
2955 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002956 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002957 goto unlock;
2958 }
2959
Johan Hedberg04ab2742014-12-05 13:36:04 +02002960 cmd->cmd_complete = pairing_complete;
2961
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002962 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002963 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002964 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002965 conn->security_cfm_cb = pairing_complete_cb;
2966 conn->disconn_cfm_cb = pairing_complete_cb;
2967 } else {
2968 conn->connect_cfm_cb = le_pairing_complete_cb;
2969 conn->security_cfm_cb = le_pairing_complete_cb;
2970 conn->disconn_cfm_cb = le_pairing_complete_cb;
2971 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002972
Johan Hedberge9a416b2011-02-19 12:05:56 -03002973 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002974 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002975
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002976 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002977 hci_conn_security(conn, sec_level, auth_type, true)) {
2978 cmd->cmd_complete(cmd, 0);
2979 mgmt_pending_remove(cmd);
2980 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002981
2982 err = 0;
2983
2984unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002985 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002986 return err;
2987}
2988
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002989static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2990 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002991{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002992 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002993 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002994 struct hci_conn *conn;
2995 int err;
2996
2997 BT_DBG("");
2998
Johan Hedberg28424702012-02-02 04:02:29 +02002999 hci_dev_lock(hdev);
3000
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003001 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003002 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3003 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003004 goto unlock;
3005 }
3006
Johan Hedberg333ae952015-03-17 13:48:47 +02003007 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003008 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003009 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3010 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003011 goto unlock;
3012 }
3013
3014 conn = cmd->user_data;
3015
3016 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003017 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3018 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003019 goto unlock;
3020 }
3021
Johan Hedberga511b352014-12-11 21:45:45 +02003022 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3023 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003024
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003025 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3026 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003027unlock:
3028 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003029 return err;
3030}
3031
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003032static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003033 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003034 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003035{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003036 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003037 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003038 int err;
3039
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003040 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003041
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003042 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003043 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3044 MGMT_STATUS_NOT_POWERED, addr,
3045 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003046 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003047 }
3048
Johan Hedberg1707c602013-03-15 17:07:15 -05003049 if (addr->type == BDADDR_BREDR)
3050 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003051 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003052 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3053 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003054
Johan Hedberg272d90d2012-02-09 15:26:12 +02003055 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003056 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3057 MGMT_STATUS_NOT_CONNECTED, addr,
3058 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003059 goto done;
3060 }
3061
Johan Hedberg1707c602013-03-15 17:07:15 -05003062 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003063 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003064 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003065 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3066 MGMT_STATUS_SUCCESS, addr,
3067 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003068 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003069 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3070 MGMT_STATUS_FAILED, addr,
3071 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003072
Brian Gix47c15e22011-11-16 13:53:14 -08003073 goto done;
3074 }
3075
Johan Hedberg1707c602013-03-15 17:07:15 -05003076 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003077 if (!cmd) {
3078 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003079 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003080 }
3081
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003082 cmd->cmd_complete = addr_cmd_complete;
3083
Brian Gix0df4c182011-11-16 13:53:13 -08003084 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003085 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3086 struct hci_cp_user_passkey_reply cp;
3087
Johan Hedberg1707c602013-03-15 17:07:15 -05003088 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003089 cp.passkey = passkey;
3090 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3091 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003092 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3093 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003094
Johan Hedberga664b5b2011-02-19 12:06:02 -03003095 if (err < 0)
3096 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003097
Brian Gix0df4c182011-11-16 13:53:13 -08003098done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003099 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003100 return err;
3101}
3102
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303103static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3104 void *data, u16 len)
3105{
3106 struct mgmt_cp_pin_code_neg_reply *cp = data;
3107
3108 BT_DBG("");
3109
Johan Hedberg1707c602013-03-15 17:07:15 -05003110 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303111 MGMT_OP_PIN_CODE_NEG_REPLY,
3112 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3113}
3114
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003115static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3116 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003117{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003118 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003119
3120 BT_DBG("");
3121
3122 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003123 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3124 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003125
Johan Hedberg1707c602013-03-15 17:07:15 -05003126 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 MGMT_OP_USER_CONFIRM_REPLY,
3128 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003129}
3130
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003131static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003133{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003134 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003135
3136 BT_DBG("");
3137
Johan Hedberg1707c602013-03-15 17:07:15 -05003138 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003139 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3140 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003141}
3142
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003143static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3144 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003145{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003146 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003147
3148 BT_DBG("");
3149
Johan Hedberg1707c602013-03-15 17:07:15 -05003150 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003151 MGMT_OP_USER_PASSKEY_REPLY,
3152 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003153}
3154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003155static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003156 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003157{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003158 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003159
3160 BT_DBG("");
3161
Johan Hedberg1707c602013-03-15 17:07:15 -05003162 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003163 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3164 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003165}
3166
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003167static void adv_expire(struct hci_dev *hdev, u32 flags)
3168{
3169 struct adv_info *adv_instance;
3170 struct hci_request req;
3171 int err;
3172
3173 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3174 if (!adv_instance)
3175 return;
3176
3177 /* stop if current instance doesn't need to be changed */
3178 if (!(adv_instance->flags & flags))
3179 return;
3180
3181 cancel_adv_timeout(hdev);
3182
3183 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3184 if (!adv_instance)
3185 return;
3186
3187 hci_req_init(&req, hdev);
3188 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3189 true);
3190 if (err)
3191 return;
3192
3193 hci_req_run(&req, NULL);
3194}
3195
Marcel Holtmann1904a852015-01-11 13:50:44 -08003196static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003197{
3198 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003199 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003200
3201 BT_DBG("status 0x%02x", status);
3202
3203 hci_dev_lock(hdev);
3204
Johan Hedberg333ae952015-03-17 13:48:47 +02003205 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003206 if (!cmd)
3207 goto unlock;
3208
3209 cp = cmd->param;
3210
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003211 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003212 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3213 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003214 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003215 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3216 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003217
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003218 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3219 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3220 }
3221
Johan Hedberg13928972013-03-15 17:07:00 -05003222 mgmt_pending_remove(cmd);
3223
3224unlock:
3225 hci_dev_unlock(hdev);
3226}
3227
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003228static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003229 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003230{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003231 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003232 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003233 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003234 int err;
3235
3236 BT_DBG("");
3237
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003238 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003239
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003240 /* If the old values are the same as the new ones just return a
3241 * direct command complete event.
3242 */
3243 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3244 !memcmp(hdev->short_name, cp->short_name,
3245 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003246 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3247 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003248 goto failed;
3249 }
3250
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003251 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003252
Johan Hedbergb5235a62012-02-21 14:32:24 +02003253 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003254 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003255
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003256 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3257 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003258 if (err < 0)
3259 goto failed;
3260
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003261 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3262 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003263 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003264
Johan Hedbergb5235a62012-02-21 14:32:24 +02003265 goto failed;
3266 }
3267
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003268 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003269 if (!cmd) {
3270 err = -ENOMEM;
3271 goto failed;
3272 }
3273
Johan Hedberg13928972013-03-15 17:07:00 -05003274 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3275
Johan Hedberg890ea892013-03-15 17:06:52 -05003276 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003277
3278 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003279 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003280 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003281 }
3282
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003283 /* The name is stored in the scan response data and so
3284 * no need to udpate the advertising data here.
3285 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003286 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003287 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003288
Johan Hedberg13928972013-03-15 17:07:00 -05003289 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003290 if (err < 0)
3291 mgmt_pending_remove(cmd);
3292
3293failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003294 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003295 return err;
3296}
3297
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003298static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3299 u16 len)
3300{
3301 struct mgmt_cp_set_appearance *cp = data;
Alain Michaud6613bab2020-01-22 19:47:44 +00003302 u16 appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003303 int err;
3304
3305 BT_DBG("");
3306
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003307 if (!lmp_le_capable(hdev))
3308 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3309 MGMT_STATUS_NOT_SUPPORTED);
3310
Alain Michaud6613bab2020-01-22 19:47:44 +00003311 appearance = le16_to_cpu(cp->appearance);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003312
3313 hci_dev_lock(hdev);
3314
Alain Michaud6613bab2020-01-22 19:47:44 +00003315 if (hdev->appearance != appearance) {
3316 hdev->appearance = appearance;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003317
3318 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3319 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003320
3321 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003322 }
3323
3324 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3325 0);
3326
3327 hci_dev_unlock(hdev);
3328
3329 return err;
3330}
3331
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303332static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3333 void *data, u16 len)
3334{
3335 struct mgmt_rp_get_phy_confguration rp;
3336
3337 BT_DBG("sock %p %s", sk, hdev->name);
3338
3339 hci_dev_lock(hdev);
3340
3341 memset(&rp, 0, sizeof(rp));
3342
3343 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3344 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3345 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3346
3347 hci_dev_unlock(hdev);
3348
3349 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3350 &rp, sizeof(rp));
3351}
3352
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303353int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3354{
3355 struct mgmt_ev_phy_configuration_changed ev;
3356
3357 memset(&ev, 0, sizeof(ev));
3358
3359 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3360
3361 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3362 sizeof(ev), skip);
3363}
3364
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303365static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3366 u16 opcode, struct sk_buff *skb)
3367{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303368 struct mgmt_pending_cmd *cmd;
3369
3370 BT_DBG("status 0x%02x", status);
3371
3372 hci_dev_lock(hdev);
3373
3374 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3375 if (!cmd)
3376 goto unlock;
3377
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303378 if (status) {
3379 mgmt_cmd_status(cmd->sk, hdev->id,
3380 MGMT_OP_SET_PHY_CONFIGURATION,
3381 mgmt_status(status));
3382 } else {
3383 mgmt_cmd_complete(cmd->sk, hdev->id,
3384 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3385 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303386
3387 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303388 }
3389
3390 mgmt_pending_remove(cmd);
3391
3392unlock:
3393 hci_dev_unlock(hdev);
3394}
3395
3396static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3397 void *data, u16 len)
3398{
3399 struct mgmt_cp_set_phy_confguration *cp = data;
3400 struct hci_cp_le_set_default_phy cp_phy;
3401 struct mgmt_pending_cmd *cmd;
3402 struct hci_request req;
3403 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3404 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303405 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303406 int err;
3407
3408 BT_DBG("sock %p %s", sk, hdev->name);
3409
3410 configurable_phys = get_configurable_phys(hdev);
3411 supported_phys = get_supported_phys(hdev);
3412 selected_phys = __le32_to_cpu(cp->selected_phys);
3413
3414 if (selected_phys & ~supported_phys)
3415 return mgmt_cmd_status(sk, hdev->id,
3416 MGMT_OP_SET_PHY_CONFIGURATION,
3417 MGMT_STATUS_INVALID_PARAMS);
3418
3419 unconfigure_phys = supported_phys & ~configurable_phys;
3420
3421 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3422 return mgmt_cmd_status(sk, hdev->id,
3423 MGMT_OP_SET_PHY_CONFIGURATION,
3424 MGMT_STATUS_INVALID_PARAMS);
3425
3426 if (selected_phys == get_selected_phys(hdev))
3427 return mgmt_cmd_complete(sk, hdev->id,
3428 MGMT_OP_SET_PHY_CONFIGURATION,
3429 0, NULL, 0);
3430
3431 hci_dev_lock(hdev);
3432
3433 if (!hdev_is_powered(hdev)) {
3434 err = mgmt_cmd_status(sk, hdev->id,
3435 MGMT_OP_SET_PHY_CONFIGURATION,
3436 MGMT_STATUS_REJECTED);
3437 goto unlock;
3438 }
3439
3440 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3441 err = mgmt_cmd_status(sk, hdev->id,
3442 MGMT_OP_SET_PHY_CONFIGURATION,
3443 MGMT_STATUS_BUSY);
3444 goto unlock;
3445 }
3446
3447 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3448 pkt_type |= (HCI_DH3 | HCI_DM3);
3449 else
3450 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3451
3452 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3453 pkt_type |= (HCI_DH5 | HCI_DM5);
3454 else
3455 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3456
3457 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3458 pkt_type &= ~HCI_2DH1;
3459 else
3460 pkt_type |= HCI_2DH1;
3461
3462 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3463 pkt_type &= ~HCI_2DH3;
3464 else
3465 pkt_type |= HCI_2DH3;
3466
3467 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3468 pkt_type &= ~HCI_2DH5;
3469 else
3470 pkt_type |= HCI_2DH5;
3471
3472 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3473 pkt_type &= ~HCI_3DH1;
3474 else
3475 pkt_type |= HCI_3DH1;
3476
3477 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3478 pkt_type &= ~HCI_3DH3;
3479 else
3480 pkt_type |= HCI_3DH3;
3481
3482 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3483 pkt_type &= ~HCI_3DH5;
3484 else
3485 pkt_type |= HCI_3DH5;
3486
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303487 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303488 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303489 changed = true;
3490 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303491
3492 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3493 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303494 if (changed)
3495 mgmt_phy_configuration_changed(hdev, sk);
3496
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303497 err = mgmt_cmd_complete(sk, hdev->id,
3498 MGMT_OP_SET_PHY_CONFIGURATION,
3499 0, NULL, 0);
3500
3501 goto unlock;
3502 }
3503
3504 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3505 len);
3506 if (!cmd) {
3507 err = -ENOMEM;
3508 goto unlock;
3509 }
3510
3511 hci_req_init(&req, hdev);
3512
3513 memset(&cp_phy, 0, sizeof(cp_phy));
3514
3515 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3516 cp_phy.all_phys |= 0x01;
3517
3518 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3519 cp_phy.all_phys |= 0x02;
3520
3521 if (selected_phys & MGMT_PHY_LE_1M_TX)
3522 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3523
3524 if (selected_phys & MGMT_PHY_LE_2M_TX)
3525 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3526
3527 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3528 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3529
3530 if (selected_phys & MGMT_PHY_LE_1M_RX)
3531 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3532
3533 if (selected_phys & MGMT_PHY_LE_2M_RX)
3534 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3535
3536 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3537 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3538
3539 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3540
3541 err = hci_req_run_skb(&req, set_default_phy_complete);
3542 if (err < 0)
3543 mgmt_pending_remove(cmd);
3544
3545unlock:
3546 hci_dev_unlock(hdev);
3547
3548 return err;
3549}
3550
Alain Michaud600a8742020-01-07 00:43:17 +00003551static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
3552 u16 len)
3553{
3554 int err = MGMT_STATUS_SUCCESS;
3555 struct mgmt_cp_set_blocked_keys *keys = data;
3556 const u16 max_key_count = ((U16_MAX - sizeof(*keys)) /
3557 sizeof(struct mgmt_blocked_key_info));
3558 u16 key_count, expected_len;
3559 int i;
3560
3561 BT_DBG("request for %s", hdev->name);
3562
3563 key_count = __le16_to_cpu(keys->key_count);
3564 if (key_count > max_key_count) {
3565 bt_dev_err(hdev, "too big key_count value %u", key_count);
3566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3567 MGMT_STATUS_INVALID_PARAMS);
3568 }
3569
3570 expected_len = struct_size(keys, keys, key_count);
3571 if (expected_len != len) {
3572 bt_dev_err(hdev, "expected %u bytes, got %u bytes",
3573 expected_len, len);
3574 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3575 MGMT_STATUS_INVALID_PARAMS);
3576 }
3577
3578 hci_dev_lock(hdev);
3579
3580 hci_blocked_keys_clear(hdev);
3581
3582 for (i = 0; i < keys->key_count; ++i) {
3583 struct blocked_key *b = kzalloc(sizeof(*b), GFP_KERNEL);
3584
3585 if (!b) {
3586 err = MGMT_STATUS_NO_RESOURCES;
3587 break;
3588 }
3589
3590 b->type = keys->keys[i].type;
3591 memcpy(b->val, keys->keys[i].val, sizeof(b->val));
3592 list_add_rcu(&b->list, &hdev->blocked_keys);
3593 }
3594 hci_dev_unlock(hdev);
3595
3596 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
3597 err, NULL, 0);
3598}
3599
Alain Michaud00bce3f2020-03-05 16:14:59 +00003600static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
3601 void *data, u16 len)
3602{
3603 struct mgmt_mode *cp = data;
3604 int err;
3605 bool changed = false;
3606
3607 BT_DBG("request for %s", hdev->name);
3608
3609 if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks))
3610 return mgmt_cmd_status(sk, hdev->id,
3611 MGMT_OP_SET_WIDEBAND_SPEECH,
3612 MGMT_STATUS_NOT_SUPPORTED);
3613
3614 if (cp->val != 0x00 && cp->val != 0x01)
3615 return mgmt_cmd_status(sk, hdev->id,
3616 MGMT_OP_SET_WIDEBAND_SPEECH,
3617 MGMT_STATUS_INVALID_PARAMS);
3618
3619 hci_dev_lock(hdev);
3620
3621 if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
3622 err = mgmt_cmd_status(sk, hdev->id,
3623 MGMT_OP_SET_WIDEBAND_SPEECH,
3624 MGMT_STATUS_BUSY);
3625 goto unlock;
3626 }
3627
3628 if (hdev_is_powered(hdev) &&
3629 !!cp->val != hci_dev_test_flag(hdev,
3630 HCI_WIDEBAND_SPEECH_ENABLED)) {
3631 err = mgmt_cmd_status(sk, hdev->id,
3632 MGMT_OP_SET_WIDEBAND_SPEECH,
3633 MGMT_STATUS_REJECTED);
3634 goto unlock;
3635 }
3636
3637 if (cp->val)
3638 changed = !hci_dev_test_and_set_flag(hdev,
3639 HCI_WIDEBAND_SPEECH_ENABLED);
3640 else
3641 changed = hci_dev_test_and_clear_flag(hdev,
3642 HCI_WIDEBAND_SPEECH_ENABLED);
3643
3644 err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev);
3645 if (err < 0)
3646 goto unlock;
3647
3648 if (changed)
3649 err = new_settings(hdev, sk);
3650
3651unlock:
3652 hci_dev_unlock(hdev);
3653 return err;
3654}
3655
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003656static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3657 u16 opcode, struct sk_buff *skb)
3658{
3659 struct mgmt_rp_read_local_oob_data mgmt_rp;
3660 size_t rp_size = sizeof(mgmt_rp);
3661 struct mgmt_pending_cmd *cmd;
3662
3663 BT_DBG("%s status %u", hdev->name, status);
3664
3665 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3666 if (!cmd)
3667 return;
3668
3669 if (status || !skb) {
3670 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3671 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3672 goto remove;
3673 }
3674
3675 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3676
3677 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3678 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3679
3680 if (skb->len < sizeof(*rp)) {
3681 mgmt_cmd_status(cmd->sk, hdev->id,
3682 MGMT_OP_READ_LOCAL_OOB_DATA,
3683 MGMT_STATUS_FAILED);
3684 goto remove;
3685 }
3686
3687 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3688 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3689
3690 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3691 } else {
3692 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3693
3694 if (skb->len < sizeof(*rp)) {
3695 mgmt_cmd_status(cmd->sk, hdev->id,
3696 MGMT_OP_READ_LOCAL_OOB_DATA,
3697 MGMT_STATUS_FAILED);
3698 goto remove;
3699 }
3700
3701 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3702 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3703
3704 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3705 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3706 }
3707
3708 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3709 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3710
3711remove:
3712 mgmt_pending_remove(cmd);
3713}
3714
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003715static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003716 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003717{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003718 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003719 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003720 int err;
3721
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003722 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003723
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003724 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003725
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003726 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003727 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3728 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003729 goto unlock;
3730 }
3731
Andre Guedes9a1a1992012-07-24 15:03:48 -03003732 if (!lmp_ssp_capable(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_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003735 goto unlock;
3736 }
3737
Johan Hedberg333ae952015-03-17 13:48:47 +02003738 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, 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_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003741 goto unlock;
3742 }
3743
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003744 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003745 if (!cmd) {
3746 err = -ENOMEM;
3747 goto unlock;
3748 }
3749
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003750 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003751
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003752 if (bredr_sc_enabled(hdev))
3753 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3754 else
3755 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3756
3757 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003758 if (err < 0)
3759 mgmt_pending_remove(cmd);
3760
3761unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003762 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003763 return err;
3764}
3765
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003766static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003767 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003768{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003769 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003770 int err;
3771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003772 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003773
Johan Hedberg5d57e792015-01-23 10:10:38 +02003774 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003775 return mgmt_cmd_complete(sk, hdev->id,
3776 MGMT_OP_ADD_REMOTE_OOB_DATA,
3777 MGMT_STATUS_INVALID_PARAMS,
3778 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003779
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003780 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003781
Marcel Holtmannec109112014-01-10 02:07:30 -08003782 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3783 struct mgmt_cp_add_remote_oob_data *cp = data;
3784 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003785
Johan Hedbergc19a4952014-11-17 20:52:19 +02003786 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003787 err = mgmt_cmd_complete(sk, hdev->id,
3788 MGMT_OP_ADD_REMOTE_OOB_DATA,
3789 MGMT_STATUS_INVALID_PARAMS,
3790 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003791 goto unlock;
3792 }
3793
Marcel Holtmannec109112014-01-10 02:07:30 -08003794 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003795 cp->addr.type, cp->hash,
3796 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003797 if (err < 0)
3798 status = MGMT_STATUS_FAILED;
3799 else
3800 status = MGMT_STATUS_SUCCESS;
3801
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003802 err = mgmt_cmd_complete(sk, hdev->id,
3803 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3804 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003805 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3806 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003807 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003808 u8 status;
3809
Johan Hedberg86df9202014-10-26 20:52:27 +01003810 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003811 /* Enforce zero-valued 192-bit parameters as
3812 * long as legacy SMP OOB isn't implemented.
3813 */
3814 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3815 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003816 err = mgmt_cmd_complete(sk, hdev->id,
3817 MGMT_OP_ADD_REMOTE_OOB_DATA,
3818 MGMT_STATUS_INVALID_PARAMS,
3819 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003820 goto unlock;
3821 }
3822
Johan Hedberg86df9202014-10-26 20:52:27 +01003823 rand192 = NULL;
3824 hash192 = NULL;
3825 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003826 /* In case one of the P-192 values is set to zero,
3827 * then just disable OOB data for P-192.
3828 */
3829 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3830 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3831 rand192 = NULL;
3832 hash192 = NULL;
3833 } else {
3834 rand192 = cp->rand192;
3835 hash192 = cp->hash192;
3836 }
3837 }
3838
3839 /* In case one of the P-256 values is set to zero, then just
3840 * disable OOB data for P-256.
3841 */
3842 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3843 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3844 rand256 = NULL;
3845 hash256 = NULL;
3846 } else {
3847 rand256 = cp->rand256;
3848 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003849 }
3850
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003851 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003852 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003853 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003854 if (err < 0)
3855 status = MGMT_STATUS_FAILED;
3856 else
3857 status = MGMT_STATUS_SUCCESS;
3858
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003859 err = mgmt_cmd_complete(sk, hdev->id,
3860 MGMT_OP_ADD_REMOTE_OOB_DATA,
3861 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003862 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003863 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
3864 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003865 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3866 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003867 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003868
Johan Hedbergc19a4952014-11-17 20:52:19 +02003869unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003870 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003871 return err;
3872}
3873
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003874static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003875 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003876{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003877 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003878 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003879 int err;
3880
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003881 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003882
Johan Hedbergc19a4952014-11-17 20:52:19 +02003883 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003884 return mgmt_cmd_complete(sk, hdev->id,
3885 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3886 MGMT_STATUS_INVALID_PARAMS,
3887 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003888
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003889 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003890
Johan Hedbergeedbd582014-11-15 09:34:23 +02003891 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3892 hci_remote_oob_data_clear(hdev);
3893 status = MGMT_STATUS_SUCCESS;
3894 goto done;
3895 }
3896
Johan Hedberg6928a922014-10-26 20:46:09 +01003897 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003898 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003899 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003900 else
Szymon Janca6785be2012-12-13 15:11:21 +01003901 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003902
Johan Hedbergeedbd582014-11-15 09:34:23 +02003903done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003904 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3905 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003906
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003907 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003908 return err;
3909}
3910
Johan Hedberge68f0722015-11-11 08:30:30 +02003911void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003912{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003913 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003914
Andre Guedes7c307722013-04-30 15:29:28 -03003915 BT_DBG("status %d", status);
3916
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003917 hci_dev_lock(hdev);
3918
Johan Hedberg333ae952015-03-17 13:48:47 +02003919 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003920 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003921 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003922
Johan Hedberg78b781c2016-01-05 13:19:32 +02003923 if (!cmd)
3924 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3925
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003926 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003927 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003928 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003929 }
3930
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003931 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003932}
3933
Johan Hedberg591752a2015-11-11 08:11:24 +02003934static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3935 uint8_t *mgmt_status)
3936{
3937 switch (type) {
3938 case DISCOV_TYPE_LE:
3939 *mgmt_status = mgmt_le_support(hdev);
3940 if (*mgmt_status)
3941 return false;
3942 break;
3943 case DISCOV_TYPE_INTERLEAVED:
3944 *mgmt_status = mgmt_le_support(hdev);
3945 if (*mgmt_status)
3946 return false;
3947 /* Intentional fall-through */
3948 case DISCOV_TYPE_BREDR:
3949 *mgmt_status = mgmt_bredr_support(hdev);
3950 if (*mgmt_status)
3951 return false;
3952 break;
3953 default:
3954 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3955 return false;
3956 }
3957
3958 return true;
3959}
3960
Johan Hedberg78b781c2016-01-05 13:19:32 +02003961static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3962 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003963{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003964 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003965 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003966 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003967 int err;
3968
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003969 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003970
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003971 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003972
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003973 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003974 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003975 MGMT_STATUS_NOT_POWERED,
3976 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003977 goto failed;
3978 }
3979
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003980 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003981 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003982 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3983 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003984 goto failed;
3985 }
3986
Johan Hedberg591752a2015-11-11 08:11:24 +02003987 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003988 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3989 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003990 goto failed;
3991 }
3992
Marcel Holtmann22078802014-12-05 11:45:22 +01003993 /* Clear the discovery filter first to free any previously
3994 * allocated memory for the UUID list.
3995 */
3996 hci_discovery_filter_clear(hdev);
3997
Andre Guedes4aab14e2012-02-17 20:39:36 -03003998 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003999 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02004000 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
4001 hdev->discovery.limited = true;
4002 else
4003 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004004
Johan Hedberg78b781c2016-01-05 13:19:32 +02004005 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02004006 if (!cmd) {
4007 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02004008 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004009 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004010
Johan Hedberge68f0722015-11-11 08:30:30 +02004011 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004012
4013 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004014 queue_work(hdev->req_workqueue, &hdev->discov_update);
4015 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004016
4017failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004018 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004019 return err;
4020}
4021
Johan Hedberg78b781c2016-01-05 13:19:32 +02004022static int start_discovery(struct sock *sk, struct hci_dev *hdev,
4023 void *data, u16 len)
4024{
4025 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
4026 data, len);
4027}
4028
4029static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
4030 void *data, u16 len)
4031{
4032 return start_discovery_internal(sk, hdev,
4033 MGMT_OP_START_LIMITED_DISCOVERY,
4034 data, len);
4035}
4036
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004037static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4038 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004039{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004040 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4041 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004042}
4043
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004044static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4045 void *data, u16 len)
4046{
4047 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004048 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004049 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4050 u16 uuid_count, expected_len;
4051 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004052 int err;
4053
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004054 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004055
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004056 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004057
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004058 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004059 err = mgmt_cmd_complete(sk, hdev->id,
4060 MGMT_OP_START_SERVICE_DISCOVERY,
4061 MGMT_STATUS_NOT_POWERED,
4062 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004063 goto failed;
4064 }
4065
4066 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004067 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004068 err = mgmt_cmd_complete(sk, hdev->id,
4069 MGMT_OP_START_SERVICE_DISCOVERY,
4070 MGMT_STATUS_BUSY, &cp->type,
4071 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004072 goto failed;
4073 }
4074
4075 uuid_count = __le16_to_cpu(cp->uuid_count);
4076 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004077 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
4078 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004079 err = mgmt_cmd_complete(sk, hdev->id,
4080 MGMT_OP_START_SERVICE_DISCOVERY,
4081 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4082 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004083 goto failed;
4084 }
4085
4086 expected_len = sizeof(*cp) + uuid_count * 16;
4087 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004088 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
4089 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004090 err = mgmt_cmd_complete(sk, hdev->id,
4091 MGMT_OP_START_SERVICE_DISCOVERY,
4092 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4093 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004094 goto failed;
4095 }
4096
Johan Hedberg591752a2015-11-11 08:11:24 +02004097 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
4098 err = mgmt_cmd_complete(sk, hdev->id,
4099 MGMT_OP_START_SERVICE_DISCOVERY,
4100 status, &cp->type, sizeof(cp->type));
4101 goto failed;
4102 }
4103
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004104 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004105 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004106 if (!cmd) {
4107 err = -ENOMEM;
4108 goto failed;
4109 }
4110
Johan Hedberg2922a942014-12-05 13:36:06 +02004111 cmd->cmd_complete = service_discovery_cmd_complete;
4112
Marcel Holtmann22078802014-12-05 11:45:22 +01004113 /* Clear the discovery filter first to free any previously
4114 * allocated memory for the UUID list.
4115 */
4116 hci_discovery_filter_clear(hdev);
4117
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004118 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004119 hdev->discovery.type = cp->type;
4120 hdev->discovery.rssi = cp->rssi;
4121 hdev->discovery.uuid_count = uuid_count;
4122
4123 if (uuid_count > 0) {
4124 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4125 GFP_KERNEL);
4126 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004127 err = mgmt_cmd_complete(sk, hdev->id,
4128 MGMT_OP_START_SERVICE_DISCOVERY,
4129 MGMT_STATUS_FAILED,
4130 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004131 mgmt_pending_remove(cmd);
4132 goto failed;
4133 }
4134 }
4135
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004136 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004137 queue_work(hdev->req_workqueue, &hdev->discov_update);
4138 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004139
4140failed:
4141 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004142 return err;
4143}
4144
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004145void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004146{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004147 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004148
Andre Guedes0e05bba2013-04-30 15:29:33 -03004149 BT_DBG("status %d", status);
4150
4151 hci_dev_lock(hdev);
4152
Johan Hedberg333ae952015-03-17 13:48:47 +02004153 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004154 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004155 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004156 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004157 }
4158
Andre Guedes0e05bba2013-04-30 15:29:33 -03004159 hci_dev_unlock(hdev);
4160}
4161
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004162static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004163 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004164{
Johan Hedbergd9306502012-02-20 23:25:18 +02004165 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004166 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004167 int err;
4168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004169 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004170
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004171 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004172
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004173 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004174 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4175 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4176 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004177 goto unlock;
4178 }
4179
4180 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004181 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4182 MGMT_STATUS_INVALID_PARAMS,
4183 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004184 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004185 }
4186
Johan Hedberg2922a942014-12-05 13:36:06 +02004187 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004188 if (!cmd) {
4189 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004190 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004191 }
4192
Johan Hedberg2922a942014-12-05 13:36:06 +02004193 cmd->cmd_complete = generic_cmd_complete;
4194
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004195 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4196 queue_work(hdev->req_workqueue, &hdev->discov_update);
4197 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004198
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004199unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004200 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004201 return err;
4202}
4203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004204static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004205 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004206{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004207 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004208 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004209 int err;
4210
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004211 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004212
Johan Hedberg561aafb2012-01-04 13:31:59 +02004213 hci_dev_lock(hdev);
4214
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004215 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004216 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4217 MGMT_STATUS_FAILED, &cp->addr,
4218 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004219 goto failed;
4220 }
4221
Johan Hedberga198e7b2012-02-17 14:27:06 +02004222 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004223 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004224 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4225 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4226 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004227 goto failed;
4228 }
4229
4230 if (cp->name_known) {
4231 e->name_state = NAME_KNOWN;
4232 list_del(&e->list);
4233 } else {
4234 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004235 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004236 }
4237
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004238 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4239 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004240
4241failed:
4242 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004243 return err;
4244}
4245
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004246static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004247 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004248{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004249 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004250 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004251 int err;
4252
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004253 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004254
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004255 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004256 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4257 MGMT_STATUS_INVALID_PARAMS,
4258 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004259
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004260 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004261
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004262 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4263 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004264 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004265 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004266 goto done;
4267 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004268
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004269 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4270 sk);
4271 status = MGMT_STATUS_SUCCESS;
4272
4273done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004274 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4275 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004276
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004277 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004278
4279 return err;
4280}
4281
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004282static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004283 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004284{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004285 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004286 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004287 int err;
4288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004289 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004290
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004291 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004292 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4293 MGMT_STATUS_INVALID_PARAMS,
4294 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004295
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004296 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004297
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004298 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4299 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004300 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004301 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004302 goto done;
4303 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004304
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004305 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4306 sk);
4307 status = MGMT_STATUS_SUCCESS;
4308
4309done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004310 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4311 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004312
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004313 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004314
4315 return err;
4316}
4317
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004318static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4319 u16 len)
4320{
4321 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004322 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004323 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004324 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004325
4326 BT_DBG("%s", hdev->name);
4327
Szymon Jancc72d4b82012-03-16 16:02:57 +01004328 source = __le16_to_cpu(cp->source);
4329
4330 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004331 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4332 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004333
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004334 hci_dev_lock(hdev);
4335
Szymon Jancc72d4b82012-03-16 16:02:57 +01004336 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004337 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4338 hdev->devid_product = __le16_to_cpu(cp->product);
4339 hdev->devid_version = __le16_to_cpu(cp->version);
4340
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004341 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4342 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004343
Johan Hedberg890ea892013-03-15 17:06:52 -05004344 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004345 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004346 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004347
4348 hci_dev_unlock(hdev);
4349
4350 return err;
4351}
4352
Arman Uguray24b4f382015-03-23 15:57:12 -07004353static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4354 u16 opcode)
4355{
4356 BT_DBG("status %d", status);
4357}
4358
Marcel Holtmann1904a852015-01-11 13:50:44 -08004359static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4360 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004361{
4362 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004363 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004364 u8 instance;
4365 struct adv_info *adv_instance;
4366 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004367
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304368 hci_dev_lock(hdev);
4369
Johan Hedberg4375f102013-09-25 13:26:10 +03004370 if (status) {
4371 u8 mgmt_err = mgmt_status(status);
4372
4373 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4374 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304375 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004376 }
4377
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004378 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004379 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004380 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004381 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004382
Johan Hedberg4375f102013-09-25 13:26:10 +03004383 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4384 &match);
4385
4386 new_settings(hdev, match.sk);
4387
4388 if (match.sk)
4389 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304390
Arman Uguray24b4f382015-03-23 15:57:12 -07004391 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004392 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004393 */
4394 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004395 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004396 goto unlock;
4397
Florian Grandel7816b822015-06-18 03:16:45 +02004398 instance = hdev->cur_adv_instance;
4399 if (!instance) {
4400 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4401 struct adv_info, list);
4402 if (!adv_instance)
4403 goto unlock;
4404
4405 instance = adv_instance->instance;
4406 }
4407
Arman Uguray24b4f382015-03-23 15:57:12 -07004408 hci_req_init(&req, hdev);
4409
Johan Hedbergf2252572015-11-18 12:49:20 +02004410 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004411
Florian Grandel7816b822015-06-18 03:16:45 +02004412 if (!err)
4413 err = hci_req_run(&req, enable_advertising_instance);
4414
4415 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004416 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004417
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304418unlock:
4419 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004420}
4421
Marcel Holtmann21b51872013-10-10 09:47:53 -07004422static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4423 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004424{
4425 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004426 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004427 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004428 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004429 int err;
4430
4431 BT_DBG("request for %s", hdev->name);
4432
Johan Hedberge6fe7982013-10-02 15:45:22 +03004433 status = mgmt_le_support(hdev);
4434 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004435 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4436 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004437
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004438 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004439 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4440 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004441
4442 hci_dev_lock(hdev);
4443
4444 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004445
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004446 /* The following conditions are ones which mean that we should
4447 * not do any HCI communication but directly send a mgmt
4448 * response to user space (after toggling the flag if
4449 * necessary).
4450 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004451 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004452 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4453 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004454 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004455 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004456 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004457 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004458
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004459 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004460 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004461 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004462 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004463 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004464 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004465 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004466 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004467 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004468 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004469 }
4470
4471 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4472 if (err < 0)
4473 goto unlock;
4474
4475 if (changed)
4476 err = new_settings(hdev, sk);
4477
4478 goto unlock;
4479 }
4480
Johan Hedberg333ae952015-03-17 13:48:47 +02004481 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4482 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004483 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4484 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004485 goto unlock;
4486 }
4487
4488 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4489 if (!cmd) {
4490 err = -ENOMEM;
4491 goto unlock;
4492 }
4493
4494 hci_req_init(&req, hdev);
4495
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004496 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004497 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004498 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004499 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004500
Florian Grandel7816b822015-06-18 03:16:45 +02004501 cancel_adv_timeout(hdev);
4502
Arman Uguray24b4f382015-03-23 15:57:12 -07004503 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004504 /* Switch to instance "0" for the Set Advertising setting.
4505 * We cannot use update_[adv|scan_rsp]_data() here as the
4506 * HCI_ADVERTISING flag is not yet set.
4507 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004508 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304509
4510 if (ext_adv_capable(hdev)) {
4511 __hci_req_start_ext_adv(&req, 0x00);
4512 } else {
4513 __hci_req_update_adv_data(&req, 0x00);
4514 __hci_req_update_scan_rsp_data(&req, 0x00);
4515 __hci_req_enable_advertising(&req);
4516 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004517 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004518 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004519 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004520
4521 err = hci_req_run(&req, set_advertising_complete);
4522 if (err < 0)
4523 mgmt_pending_remove(cmd);
4524
4525unlock:
4526 hci_dev_unlock(hdev);
4527 return err;
4528}
4529
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004530static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4531 void *data, u16 len)
4532{
4533 struct mgmt_cp_set_static_address *cp = data;
4534 int err;
4535
4536 BT_DBG("%s", hdev->name);
4537
Marcel Holtmann62af4442013-10-02 22:10:32 -07004538 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004539 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4540 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004541
4542 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004543 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4544 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004545
4546 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4547 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004548 return mgmt_cmd_status(sk, hdev->id,
4549 MGMT_OP_SET_STATIC_ADDRESS,
4550 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004551
4552 /* Two most significant bits shall be set */
4553 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004554 return mgmt_cmd_status(sk, hdev->id,
4555 MGMT_OP_SET_STATIC_ADDRESS,
4556 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004557 }
4558
4559 hci_dev_lock(hdev);
4560
4561 bacpy(&hdev->static_addr, &cp->bdaddr);
4562
Marcel Holtmann93690c22015-03-06 10:11:21 -08004563 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4564 if (err < 0)
4565 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004566
Marcel Holtmann93690c22015-03-06 10:11:21 -08004567 err = new_settings(hdev, sk);
4568
4569unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004570 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004571 return err;
4572}
4573
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004574static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4575 void *data, u16 len)
4576{
4577 struct mgmt_cp_set_scan_params *cp = data;
4578 __u16 interval, window;
4579 int err;
4580
4581 BT_DBG("%s", hdev->name);
4582
4583 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004584 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4585 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004586
4587 interval = __le16_to_cpu(cp->interval);
4588
4589 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004590 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4591 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004592
4593 window = __le16_to_cpu(cp->window);
4594
4595 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004596 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4597 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004598
Marcel Holtmann899e1072013-10-14 09:55:32 -07004599 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004600 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4601 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004602
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004603 hci_dev_lock(hdev);
4604
4605 hdev->le_scan_interval = interval;
4606 hdev->le_scan_window = window;
4607
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004608 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4609 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004610
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004611 /* If background scan is running, restart it so new parameters are
4612 * loaded.
4613 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004614 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004615 hdev->discovery.state == DISCOVERY_STOPPED) {
4616 struct hci_request req;
4617
4618 hci_req_init(&req, hdev);
4619
4620 hci_req_add_le_scan_disable(&req);
4621 hci_req_add_le_passive_scan(&req);
4622
4623 hci_req_run(&req, NULL);
4624 }
4625
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004626 hci_dev_unlock(hdev);
4627
4628 return err;
4629}
4630
Marcel Holtmann1904a852015-01-11 13:50:44 -08004631static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4632 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004633{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004634 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004635
4636 BT_DBG("status 0x%02x", status);
4637
4638 hci_dev_lock(hdev);
4639
Johan Hedberg333ae952015-03-17 13:48:47 +02004640 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004641 if (!cmd)
4642 goto unlock;
4643
4644 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004645 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4646 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004647 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004648 struct mgmt_mode *cp = cmd->param;
4649
4650 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004651 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004652 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004653 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004654
Johan Hedberg33e38b32013-03-15 17:07:05 -05004655 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4656 new_settings(hdev, cmd->sk);
4657 }
4658
4659 mgmt_pending_remove(cmd);
4660
4661unlock:
4662 hci_dev_unlock(hdev);
4663}
4664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004665static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004666 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004667{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004668 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004669 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004670 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004671 int err;
4672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004673 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004674
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004675 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004676 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4678 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004679
Johan Hedberga7e80f22013-01-09 16:05:19 +02004680 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004681 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4682 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004683
Antti Julkuf6422ec2011-06-22 13:11:56 +03004684 hci_dev_lock(hdev);
4685
Johan Hedberg333ae952015-03-17 13:48:47 +02004686 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004687 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4688 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004689 goto unlock;
4690 }
4691
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004692 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004693 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4694 hdev);
4695 goto unlock;
4696 }
4697
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004698 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004699 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004700 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4701 hdev);
4702 new_settings(hdev, sk);
4703 goto unlock;
4704 }
4705
Johan Hedberg33e38b32013-03-15 17:07:05 -05004706 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4707 data, len);
4708 if (!cmd) {
4709 err = -ENOMEM;
4710 goto unlock;
4711 }
4712
4713 hci_req_init(&req, hdev);
4714
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004715 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004716
4717 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004718 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004719 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4720 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004721 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004722 }
4723
Johan Hedberg33e38b32013-03-15 17:07:05 -05004724unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004725 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004726
Antti Julkuf6422ec2011-06-22 13:11:56 +03004727 return err;
4728}
4729
Marcel Holtmann1904a852015-01-11 13:50:44 -08004730static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004731{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004732 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004733
4734 BT_DBG("status 0x%02x", status);
4735
4736 hci_dev_lock(hdev);
4737
Johan Hedberg333ae952015-03-17 13:48:47 +02004738 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004739 if (!cmd)
4740 goto unlock;
4741
4742 if (status) {
4743 u8 mgmt_err = mgmt_status(status);
4744
4745 /* We need to restore the flag if related HCI commands
4746 * failed.
4747 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004748 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004749
Johan Hedberga69e8372015-03-06 21:08:53 +02004750 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004751 } else {
4752 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4753 new_settings(hdev, cmd->sk);
4754 }
4755
4756 mgmt_pending_remove(cmd);
4757
4758unlock:
4759 hci_dev_unlock(hdev);
4760}
4761
4762static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4763{
4764 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004765 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004766 struct hci_request req;
4767 int err;
4768
4769 BT_DBG("request for %s", hdev->name);
4770
4771 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004772 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4773 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004774
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004775 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004776 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4777 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004778
4779 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004780 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4781 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004782
4783 hci_dev_lock(hdev);
4784
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004785 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004786 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4787 goto unlock;
4788 }
4789
4790 if (!hdev_is_powered(hdev)) {
4791 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004792 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4793 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4794 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4795 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4796 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004797 }
4798
Marcel Holtmannce05d602015-03-13 02:11:03 -07004799 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004800
4801 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4802 if (err < 0)
4803 goto unlock;
4804
4805 err = new_settings(hdev, sk);
4806 goto unlock;
4807 }
4808
4809 /* Reject disabling when powered on */
4810 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004811 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4812 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004813 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004814 } else {
4815 /* When configuring a dual-mode controller to operate
4816 * with LE only and using a static address, then switching
4817 * BR/EDR back on is not allowed.
4818 *
4819 * Dual-mode controllers shall operate with the public
4820 * address as its identity address for BR/EDR and LE. So
4821 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004822 *
4823 * The same restrictions applies when secure connections
4824 * has been enabled. For BR/EDR this is a controller feature
4825 * while for LE it is a host stack feature. This means that
4826 * switching BR/EDR back on when secure connections has been
4827 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004828 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004829 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004830 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004831 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004832 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4833 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004834 goto unlock;
4835 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004836 }
4837
Johan Hedberg333ae952015-03-17 13:48:47 +02004838 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004839 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4840 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004841 goto unlock;
4842 }
4843
4844 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4845 if (!cmd) {
4846 err = -ENOMEM;
4847 goto unlock;
4848 }
4849
Johan Hedbergf2252572015-11-18 12:49:20 +02004850 /* We need to flip the bit already here so that
4851 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004852 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004853 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004854
4855 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004856
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004857 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004858 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004859
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004860 /* Since only the advertising data flags will change, there
4861 * is no need to update the scan response data.
4862 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004863 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004864
Johan Hedberg0663ca22013-10-02 13:43:14 +03004865 err = hci_req_run(&req, set_bredr_complete);
4866 if (err < 0)
4867 mgmt_pending_remove(cmd);
4868
4869unlock:
4870 hci_dev_unlock(hdev);
4871 return err;
4872}
4873
Johan Hedberga1443f52015-01-23 15:42:46 +02004874static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4875{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004876 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004877 struct mgmt_mode *cp;
4878
4879 BT_DBG("%s status %u", hdev->name, status);
4880
4881 hci_dev_lock(hdev);
4882
Johan Hedberg333ae952015-03-17 13:48:47 +02004883 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004884 if (!cmd)
4885 goto unlock;
4886
4887 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004888 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4889 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004890 goto remove;
4891 }
4892
4893 cp = cmd->param;
4894
4895 switch (cp->val) {
4896 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004897 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4898 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004899 break;
4900 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004901 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004902 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004903 break;
4904 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004905 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4906 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004907 break;
4908 }
4909
4910 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4911 new_settings(hdev, cmd->sk);
4912
4913remove:
4914 mgmt_pending_remove(cmd);
4915unlock:
4916 hci_dev_unlock(hdev);
4917}
4918
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004919static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4920 void *data, u16 len)
4921{
4922 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004923 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004924 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004925 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004926 int err;
4927
4928 BT_DBG("request for %s", hdev->name);
4929
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004930 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004931 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004932 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4933 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004934
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004935 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004936 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004937 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004938 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4939 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004940
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004941 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004942 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004943 MGMT_STATUS_INVALID_PARAMS);
4944
4945 hci_dev_lock(hdev);
4946
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004947 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004948 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004949 bool changed;
4950
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004951 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004952 changed = !hci_dev_test_and_set_flag(hdev,
4953 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004954 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004955 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004956 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004957 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004958 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004959 changed = hci_dev_test_and_clear_flag(hdev,
4960 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004961 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004962 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004963
4964 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4965 if (err < 0)
4966 goto failed;
4967
4968 if (changed)
4969 err = new_settings(hdev, sk);
4970
4971 goto failed;
4972 }
4973
Johan Hedberg333ae952015-03-17 13:48:47 +02004974 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004975 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4976 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004977 goto failed;
4978 }
4979
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004980 val = !!cp->val;
4981
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004982 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4983 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004984 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4985 goto failed;
4986 }
4987
4988 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4989 if (!cmd) {
4990 err = -ENOMEM;
4991 goto failed;
4992 }
4993
Johan Hedberga1443f52015-01-23 15:42:46 +02004994 hci_req_init(&req, hdev);
4995 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4996 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004997 if (err < 0) {
4998 mgmt_pending_remove(cmd);
4999 goto failed;
5000 }
5001
5002failed:
5003 hci_dev_unlock(hdev);
5004 return err;
5005}
5006
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005007static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5008 void *data, u16 len)
5009{
5010 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005011 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005012 int err;
5013
5014 BT_DBG("request for %s", hdev->name);
5015
Johan Hedbergb97109792014-06-24 14:00:28 +03005016 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005017 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5018 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005019
5020 hci_dev_lock(hdev);
5021
5022 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005023 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005024 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005025 changed = hci_dev_test_and_clear_flag(hdev,
5026 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005027
Johan Hedbergb97109792014-06-24 14:00:28 +03005028 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005029 use_changed = !hci_dev_test_and_set_flag(hdev,
5030 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005031 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005032 use_changed = hci_dev_test_and_clear_flag(hdev,
5033 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005034
5035 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005036 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005037 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5038 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5039 sizeof(mode), &mode);
5040 }
5041
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005042 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5043 if (err < 0)
5044 goto unlock;
5045
5046 if (changed)
5047 err = new_settings(hdev, sk);
5048
5049unlock:
5050 hci_dev_unlock(hdev);
5051 return err;
5052}
5053
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005054static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5055 u16 len)
5056{
5057 struct mgmt_cp_set_privacy *cp = cp_data;
5058 bool changed;
5059 int err;
5060
5061 BT_DBG("request for %s", hdev->name);
5062
5063 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005064 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5065 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005066
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005067 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005068 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5069 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005070
5071 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005072 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5073 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005074
5075 hci_dev_lock(hdev);
5076
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005077 /* If user space supports this command it is also expected to
5078 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5079 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005080 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005081
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005082 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005083 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005084 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005085 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305086 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005087 if (cp->privacy == 0x02)
5088 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
5089 else
5090 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005091 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005092 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005093 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005094 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05305095 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02005096 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005097 }
5098
5099 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5100 if (err < 0)
5101 goto unlock;
5102
5103 if (changed)
5104 err = new_settings(hdev, sk);
5105
5106unlock:
5107 hci_dev_unlock(hdev);
5108 return err;
5109}
5110
Johan Hedberg41edf162014-02-18 10:19:35 +02005111static bool irk_is_valid(struct mgmt_irk_info *irk)
5112{
5113 switch (irk->addr.type) {
5114 case BDADDR_LE_PUBLIC:
5115 return true;
5116
5117 case BDADDR_LE_RANDOM:
5118 /* Two most significant bits shall be set */
5119 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5120 return false;
5121 return true;
5122 }
5123
5124 return false;
5125}
5126
5127static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5128 u16 len)
5129{
5130 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005131 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5132 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005133 u16 irk_count, expected_len;
5134 int i, err;
5135
5136 BT_DBG("request for %s", hdev->name);
5137
5138 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005139 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5140 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005141
5142 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005143 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005144 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5145 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005146 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5147 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005148 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005149
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005150 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005151 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005152 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5153 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005154 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5155 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005156 }
5157
5158 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5159
5160 for (i = 0; i < irk_count; i++) {
5161 struct mgmt_irk_info *key = &cp->irks[i];
5162
5163 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005164 return mgmt_cmd_status(sk, hdev->id,
5165 MGMT_OP_LOAD_IRKS,
5166 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005167 }
5168
5169 hci_dev_lock(hdev);
5170
5171 hci_smp_irks_clear(hdev);
5172
5173 for (i = 0; i < irk_count; i++) {
5174 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005175
Alain Michaud600a8742020-01-07 00:43:17 +00005176 if (hci_is_blocked_key(hdev,
5177 HCI_BLOCKED_KEY_TYPE_IRK,
5178 irk->val)) {
5179 bt_dev_warn(hdev, "Skipping blocked IRK for %pMR",
5180 &irk->addr.bdaddr);
5181 continue;
5182 }
5183
Johan Hedberg85813a72015-10-21 18:02:59 +03005184 hci_add_irk(hdev, &irk->addr.bdaddr,
5185 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005186 BDADDR_ANY);
5187 }
5188
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005189 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005190
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005191 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005192
5193 hci_dev_unlock(hdev);
5194
5195 return err;
5196}
5197
Johan Hedberg3f706b72013-01-20 14:27:16 +02005198static bool ltk_is_valid(struct mgmt_ltk_info *key)
5199{
5200 if (key->master != 0x00 && key->master != 0x01)
5201 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005202
5203 switch (key->addr.type) {
5204 case BDADDR_LE_PUBLIC:
5205 return true;
5206
5207 case BDADDR_LE_RANDOM:
5208 /* Two most significant bits shall be set */
5209 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5210 return false;
5211 return true;
5212 }
5213
5214 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005215}
5216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005217static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005218 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005219{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005220 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005221 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5222 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005223 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005224 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005225
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005226 BT_DBG("request for %s", hdev->name);
5227
5228 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005229 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5230 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005231
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005232 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005233 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005234 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5235 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005236 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5237 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005238 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005239
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005240 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005241 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005242 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5243 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005244 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5245 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005246 }
5247
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005248 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005249
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005250 for (i = 0; i < key_count; i++) {
5251 struct mgmt_ltk_info *key = &cp->keys[i];
5252
Johan Hedberg3f706b72013-01-20 14:27:16 +02005253 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005254 return mgmt_cmd_status(sk, hdev->id,
5255 MGMT_OP_LOAD_LONG_TERM_KEYS,
5256 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005257 }
5258
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005259 hci_dev_lock(hdev);
5260
5261 hci_smp_ltks_clear(hdev);
5262
5263 for (i = 0; i < key_count; i++) {
5264 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005265 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005266
Alain Michaud600a8742020-01-07 00:43:17 +00005267 if (hci_is_blocked_key(hdev,
5268 HCI_BLOCKED_KEY_TYPE_LTK,
5269 key->val)) {
5270 bt_dev_warn(hdev, "Skipping blocked LTK for %pMR",
5271 &key->addr.bdaddr);
5272 continue;
5273 }
5274
Johan Hedberg61b43352014-05-29 19:36:53 +03005275 switch (key->type) {
5276 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005277 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005278 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005279 break;
5280 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005281 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005282 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005283 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005284 case MGMT_LTK_P256_UNAUTH:
5285 authenticated = 0x00;
5286 type = SMP_LTK_P256;
5287 break;
5288 case MGMT_LTK_P256_AUTH:
5289 authenticated = 0x01;
5290 type = SMP_LTK_P256;
5291 break;
5292 case MGMT_LTK_P256_DEBUG:
5293 authenticated = 0x00;
5294 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005295 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005296 default:
5297 continue;
5298 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005299
Johan Hedberg85813a72015-10-21 18:02:59 +03005300 hci_add_ltk(hdev, &key->addr.bdaddr,
5301 le_addr_type(key->addr.type), type, authenticated,
5302 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005303 }
5304
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005305 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005306 NULL, 0);
5307
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005308 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005309
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005310 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005311}
5312
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005313static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005314{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005315 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005316 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005317 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005318
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005319 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005320
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005321 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005322 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005323 rp.tx_power = conn->tx_power;
5324 rp.max_tx_power = conn->max_tx_power;
5325 } else {
5326 rp.rssi = HCI_RSSI_INVALID;
5327 rp.tx_power = HCI_TX_POWER_INVALID;
5328 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005329 }
5330
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005331 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5332 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005333
5334 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005335 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005336
5337 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005338}
5339
Marcel Holtmann1904a852015-01-11 13:50:44 -08005340static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5341 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005342{
5343 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005344 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005345 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005346 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005347 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005348
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005349 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005350
5351 hci_dev_lock(hdev);
5352
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005353 /* Commands sent in request are either Read RSSI or Read Transmit Power
5354 * Level so we check which one was last sent to retrieve connection
5355 * handle. Both commands have handle as first parameter so it's safe to
5356 * cast data on the same command struct.
5357 *
5358 * First command sent is always Read RSSI and we fail only if it fails.
5359 * In other case we simply override error to indicate success as we
5360 * already remembered if TX power value is actually valid.
5361 */
5362 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5363 if (!cp) {
5364 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005365 status = MGMT_STATUS_SUCCESS;
5366 } else {
5367 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005368 }
5369
5370 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005371 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005372 goto unlock;
5373 }
5374
5375 handle = __le16_to_cpu(cp->handle);
5376 conn = hci_conn_hash_lookup_handle(hdev, handle);
5377 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005378 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5379 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005380 goto unlock;
5381 }
5382
Johan Hedberg333ae952015-03-17 13:48:47 +02005383 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005384 if (!cmd)
5385 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005386
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005387 cmd->cmd_complete(cmd, status);
5388 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005389
5390unlock:
5391 hci_dev_unlock(hdev);
5392}
5393
5394static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5395 u16 len)
5396{
5397 struct mgmt_cp_get_conn_info *cp = data;
5398 struct mgmt_rp_get_conn_info rp;
5399 struct hci_conn *conn;
5400 unsigned long conn_info_age;
5401 int err = 0;
5402
5403 BT_DBG("%s", hdev->name);
5404
5405 memset(&rp, 0, sizeof(rp));
5406 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5407 rp.addr.type = cp->addr.type;
5408
5409 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005410 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5411 MGMT_STATUS_INVALID_PARAMS,
5412 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005413
5414 hci_dev_lock(hdev);
5415
5416 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005417 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5418 MGMT_STATUS_NOT_POWERED, &rp,
5419 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005420 goto unlock;
5421 }
5422
5423 if (cp->addr.type == BDADDR_BREDR)
5424 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5425 &cp->addr.bdaddr);
5426 else
5427 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5428
5429 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005430 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5431 MGMT_STATUS_NOT_CONNECTED, &rp,
5432 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005433 goto unlock;
5434 }
5435
Johan Hedberg333ae952015-03-17 13:48:47 +02005436 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005437 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5438 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005439 goto unlock;
5440 }
5441
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005442 /* To avoid client trying to guess when to poll again for information we
5443 * calculate conn info age as random value between min/max set in hdev.
5444 */
5445 conn_info_age = hdev->conn_info_min_age +
5446 prandom_u32_max(hdev->conn_info_max_age -
5447 hdev->conn_info_min_age);
5448
5449 /* Query controller to refresh cached values if they are too old or were
5450 * never read.
5451 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005452 if (time_after(jiffies, conn->conn_info_timestamp +
5453 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005454 !conn->conn_info_timestamp) {
5455 struct hci_request req;
5456 struct hci_cp_read_tx_power req_txp_cp;
5457 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005458 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005459
5460 hci_req_init(&req, hdev);
5461 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5462 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5463 &req_rssi_cp);
5464
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005465 /* For LE links TX power does not change thus we don't need to
5466 * query for it once value is known.
5467 */
5468 if (!bdaddr_type_is_le(cp->addr.type) ||
5469 conn->tx_power == HCI_TX_POWER_INVALID) {
5470 req_txp_cp.handle = cpu_to_le16(conn->handle);
5471 req_txp_cp.type = 0x00;
5472 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5473 sizeof(req_txp_cp), &req_txp_cp);
5474 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005475
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005476 /* Max TX power needs to be read only once per connection */
5477 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5478 req_txp_cp.handle = cpu_to_le16(conn->handle);
5479 req_txp_cp.type = 0x01;
5480 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5481 sizeof(req_txp_cp), &req_txp_cp);
5482 }
5483
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005484 err = hci_req_run(&req, conn_info_refresh_complete);
5485 if (err < 0)
5486 goto unlock;
5487
5488 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5489 data, len);
5490 if (!cmd) {
5491 err = -ENOMEM;
5492 goto unlock;
5493 }
5494
5495 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005496 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005497 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005498
5499 conn->conn_info_timestamp = jiffies;
5500 } else {
5501 /* Cache is valid, just reply with values cached in hci_conn */
5502 rp.rssi = conn->rssi;
5503 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005504 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005505
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005506 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5507 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005508 }
5509
5510unlock:
5511 hci_dev_unlock(hdev);
5512 return err;
5513}
5514
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005515static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005516{
5517 struct hci_conn *conn = cmd->user_data;
5518 struct mgmt_rp_get_clock_info rp;
5519 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005520 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005521
5522 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005523 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005524
5525 if (status)
5526 goto complete;
5527
5528 hdev = hci_dev_get(cmd->index);
5529 if (hdev) {
5530 rp.local_clock = cpu_to_le32(hdev->clock);
5531 hci_dev_put(hdev);
5532 }
5533
5534 if (conn) {
5535 rp.piconet_clock = cpu_to_le32(conn->clock);
5536 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5537 }
5538
5539complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005540 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5541 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005542
5543 if (conn) {
5544 hci_conn_drop(conn);
5545 hci_conn_put(conn);
5546 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005547
5548 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005549}
5550
Marcel Holtmann1904a852015-01-11 13:50:44 -08005551static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005552{
Johan Hedberg95868422014-06-28 17:54:07 +03005553 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005554 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005555 struct hci_conn *conn;
5556
5557 BT_DBG("%s status %u", hdev->name, status);
5558
5559 hci_dev_lock(hdev);
5560
5561 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5562 if (!hci_cp)
5563 goto unlock;
5564
5565 if (hci_cp->which) {
5566 u16 handle = __le16_to_cpu(hci_cp->handle);
5567 conn = hci_conn_hash_lookup_handle(hdev, handle);
5568 } else {
5569 conn = NULL;
5570 }
5571
Johan Hedberg333ae952015-03-17 13:48:47 +02005572 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005573 if (!cmd)
5574 goto unlock;
5575
Johan Hedberg69487372014-12-05 13:36:07 +02005576 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005577 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005578
5579unlock:
5580 hci_dev_unlock(hdev);
5581}
5582
5583static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5584 u16 len)
5585{
5586 struct mgmt_cp_get_clock_info *cp = data;
5587 struct mgmt_rp_get_clock_info rp;
5588 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005589 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005590 struct hci_request req;
5591 struct hci_conn *conn;
5592 int err;
5593
5594 BT_DBG("%s", hdev->name);
5595
5596 memset(&rp, 0, sizeof(rp));
5597 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5598 rp.addr.type = cp->addr.type;
5599
5600 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005601 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5602 MGMT_STATUS_INVALID_PARAMS,
5603 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005604
5605 hci_dev_lock(hdev);
5606
5607 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005608 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5609 MGMT_STATUS_NOT_POWERED, &rp,
5610 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005611 goto unlock;
5612 }
5613
5614 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5615 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5616 &cp->addr.bdaddr);
5617 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005618 err = mgmt_cmd_complete(sk, hdev->id,
5619 MGMT_OP_GET_CLOCK_INFO,
5620 MGMT_STATUS_NOT_CONNECTED,
5621 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005622 goto unlock;
5623 }
5624 } else {
5625 conn = NULL;
5626 }
5627
5628 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5629 if (!cmd) {
5630 err = -ENOMEM;
5631 goto unlock;
5632 }
5633
Johan Hedberg69487372014-12-05 13:36:07 +02005634 cmd->cmd_complete = clock_info_cmd_complete;
5635
Johan Hedberg95868422014-06-28 17:54:07 +03005636 hci_req_init(&req, hdev);
5637
5638 memset(&hci_cp, 0, sizeof(hci_cp));
5639 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5640
5641 if (conn) {
5642 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005643 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005644
5645 hci_cp.handle = cpu_to_le16(conn->handle);
5646 hci_cp.which = 0x01; /* Piconet clock */
5647 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5648 }
5649
5650 err = hci_req_run(&req, get_clock_info_complete);
5651 if (err < 0)
5652 mgmt_pending_remove(cmd);
5653
5654unlock:
5655 hci_dev_unlock(hdev);
5656 return err;
5657}
5658
Johan Hedberg5a154e62014-12-19 22:26:02 +02005659static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5660{
5661 struct hci_conn *conn;
5662
5663 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5664 if (!conn)
5665 return false;
5666
5667 if (conn->dst_type != type)
5668 return false;
5669
5670 if (conn->state != BT_CONNECTED)
5671 return false;
5672
5673 return true;
5674}
5675
5676/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005677static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005678 u8 addr_type, u8 auto_connect)
5679{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005680 struct hci_conn_params *params;
5681
5682 params = hci_conn_params_add(hdev, addr, addr_type);
5683 if (!params)
5684 return -EIO;
5685
5686 if (params->auto_connect == auto_connect)
5687 return 0;
5688
5689 list_del_init(&params->action);
5690
5691 switch (auto_connect) {
5692 case HCI_AUTO_CONN_DISABLED:
5693 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005694 /* If auto connect is being disabled when we're trying to
5695 * connect to device, keep connecting.
5696 */
5697 if (params->explicit_connect)
5698 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005699 break;
5700 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005701 if (params->explicit_connect)
5702 list_add(&params->action, &hdev->pend_le_conns);
5703 else
5704 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005705 break;
5706 case HCI_AUTO_CONN_DIRECT:
5707 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005708 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005709 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005710 break;
5711 }
5712
5713 params->auto_connect = auto_connect;
5714
5715 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5716 auto_connect);
5717
5718 return 0;
5719}
5720
Marcel Holtmann8afef092014-06-29 22:28:34 +02005721static void device_added(struct sock *sk, struct hci_dev *hdev,
5722 bdaddr_t *bdaddr, u8 type, u8 action)
5723{
5724 struct mgmt_ev_device_added ev;
5725
5726 bacpy(&ev.addr.bdaddr, bdaddr);
5727 ev.addr.type = type;
5728 ev.action = action;
5729
5730 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5731}
5732
Marcel Holtmann2faade52014-06-29 19:44:03 +02005733static int add_device(struct sock *sk, struct hci_dev *hdev,
5734 void *data, u16 len)
5735{
5736 struct mgmt_cp_add_device *cp = data;
5737 u8 auto_conn, addr_type;
5738 int err;
5739
5740 BT_DBG("%s", hdev->name);
5741
Johan Hedberg66593582014-07-09 12:59:14 +03005742 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005743 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005744 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5745 MGMT_STATUS_INVALID_PARAMS,
5746 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005747
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005748 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005749 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5750 MGMT_STATUS_INVALID_PARAMS,
5751 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005752
5753 hci_dev_lock(hdev);
5754
Johan Hedberg66593582014-07-09 12:59:14 +03005755 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005756 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005757 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005758 err = mgmt_cmd_complete(sk, hdev->id,
5759 MGMT_OP_ADD_DEVICE,
5760 MGMT_STATUS_INVALID_PARAMS,
5761 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005762 goto unlock;
5763 }
5764
5765 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5766 cp->addr.type);
5767 if (err)
5768 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005769
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005770 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005771
Johan Hedberg66593582014-07-09 12:59:14 +03005772 goto added;
5773 }
5774
Johan Hedberg85813a72015-10-21 18:02:59 +03005775 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005776
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005777 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005778 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005779 else if (cp->action == 0x01)
5780 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005781 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005782 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005783
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005784 /* Kernel internally uses conn_params with resolvable private
5785 * address, but Add Device allows only identity addresses.
5786 * Make sure it is enforced before calling
5787 * hci_conn_params_lookup.
5788 */
5789 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005790 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5791 MGMT_STATUS_INVALID_PARAMS,
5792 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005793 goto unlock;
5794 }
5795
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005796 /* If the connection parameters don't exist for this device,
5797 * they will be created and configured with defaults.
5798 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005799 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005800 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005801 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5802 MGMT_STATUS_FAILED, &cp->addr,
5803 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005804 goto unlock;
5805 }
5806
Johan Hedberg51d7a942015-11-11 08:11:18 +02005807 hci_update_background_scan(hdev);
5808
Johan Hedberg66593582014-07-09 12:59:14 +03005809added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005810 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5811
Johan Hedberg51d7a942015-11-11 08:11:18 +02005812 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5813 MGMT_STATUS_SUCCESS, &cp->addr,
5814 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005815
5816unlock:
5817 hci_dev_unlock(hdev);
5818 return err;
5819}
5820
Marcel Holtmann8afef092014-06-29 22:28:34 +02005821static void device_removed(struct sock *sk, struct hci_dev *hdev,
5822 bdaddr_t *bdaddr, u8 type)
5823{
5824 struct mgmt_ev_device_removed ev;
5825
5826 bacpy(&ev.addr.bdaddr, bdaddr);
5827 ev.addr.type = type;
5828
5829 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5830}
5831
Marcel Holtmann2faade52014-06-29 19:44:03 +02005832static int remove_device(struct sock *sk, struct hci_dev *hdev,
5833 void *data, u16 len)
5834{
5835 struct mgmt_cp_remove_device *cp = data;
5836 int err;
5837
5838 BT_DBG("%s", hdev->name);
5839
5840 hci_dev_lock(hdev);
5841
5842 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005843 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005844 u8 addr_type;
5845
Johan Hedberg66593582014-07-09 12:59:14 +03005846 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005847 err = mgmt_cmd_complete(sk, hdev->id,
5848 MGMT_OP_REMOVE_DEVICE,
5849 MGMT_STATUS_INVALID_PARAMS,
5850 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005851 goto unlock;
5852 }
5853
Johan Hedberg66593582014-07-09 12:59:14 +03005854 if (cp->addr.type == BDADDR_BREDR) {
5855 err = hci_bdaddr_list_del(&hdev->whitelist,
5856 &cp->addr.bdaddr,
5857 cp->addr.type);
5858 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005859 err = mgmt_cmd_complete(sk, hdev->id,
5860 MGMT_OP_REMOVE_DEVICE,
5861 MGMT_STATUS_INVALID_PARAMS,
5862 &cp->addr,
5863 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005864 goto unlock;
5865 }
5866
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005867 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005868
Johan Hedberg66593582014-07-09 12:59:14 +03005869 device_removed(sk, hdev, &cp->addr.bdaddr,
5870 cp->addr.type);
5871 goto complete;
5872 }
5873
Johan Hedberg85813a72015-10-21 18:02:59 +03005874 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005875
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005876 /* Kernel internally uses conn_params with resolvable private
5877 * address, but Remove Device allows only identity addresses.
5878 * Make sure it is enforced before calling
5879 * hci_conn_params_lookup.
5880 */
5881 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005882 err = mgmt_cmd_complete(sk, hdev->id,
5883 MGMT_OP_REMOVE_DEVICE,
5884 MGMT_STATUS_INVALID_PARAMS,
5885 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005886 goto unlock;
5887 }
5888
Johan Hedbergc71593d2014-07-02 17:37:28 +03005889 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5890 addr_type);
5891 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005892 err = mgmt_cmd_complete(sk, hdev->id,
5893 MGMT_OP_REMOVE_DEVICE,
5894 MGMT_STATUS_INVALID_PARAMS,
5895 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005896 goto unlock;
5897 }
5898
Johan Hedberg679d2b62015-10-16 10:07:52 +03005899 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5900 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005901 err = mgmt_cmd_complete(sk, hdev->id,
5902 MGMT_OP_REMOVE_DEVICE,
5903 MGMT_STATUS_INVALID_PARAMS,
5904 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005905 goto unlock;
5906 }
5907
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005908 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005909 list_del(&params->list);
5910 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005911 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005912
5913 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005914 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005915 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005916 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005917
Marcel Holtmann2faade52014-06-29 19:44:03 +02005918 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005919 err = mgmt_cmd_complete(sk, hdev->id,
5920 MGMT_OP_REMOVE_DEVICE,
5921 MGMT_STATUS_INVALID_PARAMS,
5922 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005923 goto unlock;
5924 }
5925
Johan Hedberg66593582014-07-09 12:59:14 +03005926 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5927 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5928 list_del(&b->list);
5929 kfree(b);
5930 }
5931
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005932 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005933
Johan Hedberg19de0822014-07-06 13:06:51 +03005934 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5935 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5936 continue;
5937 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005938 if (p->explicit_connect) {
5939 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5940 continue;
5941 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005942 list_del(&p->action);
5943 list_del(&p->list);
5944 kfree(p);
5945 }
5946
5947 BT_DBG("All LE connection parameters were removed");
5948
Johan Hedberg51d7a942015-11-11 08:11:18 +02005949 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005950 }
5951
Johan Hedberg66593582014-07-09 12:59:14 +03005952complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005953 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5954 MGMT_STATUS_SUCCESS, &cp->addr,
5955 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005956unlock:
5957 hci_dev_unlock(hdev);
5958 return err;
5959}
5960
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005961static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5962 u16 len)
5963{
5964 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005965 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5966 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005967 u16 param_count, expected_len;
5968 int i;
5969
5970 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005971 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5972 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005973
5974 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005975 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005976 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
5977 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005978 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5979 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005980 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005981
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005982 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005983 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005984 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
5985 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005986 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5987 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005988 }
5989
5990 BT_DBG("%s param_count %u", hdev->name, param_count);
5991
5992 hci_dev_lock(hdev);
5993
5994 hci_conn_params_clear_disabled(hdev);
5995
5996 for (i = 0; i < param_count; i++) {
5997 struct mgmt_conn_param *param = &cp->params[i];
5998 struct hci_conn_params *hci_param;
5999 u16 min, max, latency, timeout;
6000 u8 addr_type;
6001
6002 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6003 param->addr.type);
6004
6005 if (param->addr.type == BDADDR_LE_PUBLIC) {
6006 addr_type = ADDR_LE_DEV_PUBLIC;
6007 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6008 addr_type = ADDR_LE_DEV_RANDOM;
6009 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006010 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006011 continue;
6012 }
6013
6014 min = le16_to_cpu(param->min_interval);
6015 max = le16_to_cpu(param->max_interval);
6016 latency = le16_to_cpu(param->latency);
6017 timeout = le16_to_cpu(param->timeout);
6018
6019 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6020 min, max, latency, timeout);
6021
6022 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006023 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006024 continue;
6025 }
6026
6027 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6028 addr_type);
6029 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01006030 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006031 continue;
6032 }
6033
6034 hci_param->conn_min_interval = min;
6035 hci_param->conn_max_interval = max;
6036 hci_param->conn_latency = latency;
6037 hci_param->supervision_timeout = timeout;
6038 }
6039
6040 hci_dev_unlock(hdev);
6041
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006042 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6043 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006044}
6045
Marcel Holtmanndbece372014-07-04 18:11:55 +02006046static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6047 void *data, u16 len)
6048{
6049 struct mgmt_cp_set_external_config *cp = data;
6050 bool changed;
6051 int err;
6052
6053 BT_DBG("%s", hdev->name);
6054
6055 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006056 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6057 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006058
6059 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006060 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6061 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006062
6063 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006064 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6065 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006066
6067 hci_dev_lock(hdev);
6068
6069 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006070 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006071 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006072 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006073
6074 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6075 if (err < 0)
6076 goto unlock;
6077
6078 if (!changed)
6079 goto unlock;
6080
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006081 err = new_options(hdev, sk);
6082
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006083 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006084 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006085
Marcel Holtmann516018a2015-03-13 02:11:04 -07006086 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006087 hci_dev_set_flag(hdev, HCI_CONFIG);
6088 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006089
6090 queue_work(hdev->req_workqueue, &hdev->power_on);
6091 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006092 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006093 mgmt_index_added(hdev);
6094 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006095 }
6096
6097unlock:
6098 hci_dev_unlock(hdev);
6099 return err;
6100}
6101
Marcel Holtmann9713c172014-07-06 12:11:15 +02006102static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6103 void *data, u16 len)
6104{
6105 struct mgmt_cp_set_public_address *cp = data;
6106 bool changed;
6107 int err;
6108
6109 BT_DBG("%s", hdev->name);
6110
6111 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006112 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6113 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006114
6115 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006116 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6117 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006118
6119 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006120 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6121 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006122
6123 hci_dev_lock(hdev);
6124
6125 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6126 bacpy(&hdev->public_addr, &cp->bdaddr);
6127
6128 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6129 if (err < 0)
6130 goto unlock;
6131
6132 if (!changed)
6133 goto unlock;
6134
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006135 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006136 err = new_options(hdev, sk);
6137
6138 if (is_configured(hdev)) {
6139 mgmt_index_removed(hdev);
6140
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006141 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006142
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006143 hci_dev_set_flag(hdev, HCI_CONFIG);
6144 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006145
6146 queue_work(hdev->req_workqueue, &hdev->power_on);
6147 }
6148
6149unlock:
6150 hci_dev_unlock(hdev);
6151 return err;
6152}
6153
Johan Hedberg40f66c02015-04-07 21:52:22 +03006154static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6155 u16 opcode, struct sk_buff *skb)
6156{
6157 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6158 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6159 u8 *h192, *r192, *h256, *r256;
6160 struct mgmt_pending_cmd *cmd;
6161 u16 eir_len;
6162 int err;
6163
6164 BT_DBG("%s status %u", hdev->name, status);
6165
6166 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6167 if (!cmd)
6168 return;
6169
6170 mgmt_cp = cmd->param;
6171
6172 if (status) {
6173 status = mgmt_status(status);
6174 eir_len = 0;
6175
6176 h192 = NULL;
6177 r192 = NULL;
6178 h256 = NULL;
6179 r256 = NULL;
6180 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6181 struct hci_rp_read_local_oob_data *rp;
6182
6183 if (skb->len != sizeof(*rp)) {
6184 status = MGMT_STATUS_FAILED;
6185 eir_len = 0;
6186 } else {
6187 status = MGMT_STATUS_SUCCESS;
6188 rp = (void *)skb->data;
6189
6190 eir_len = 5 + 18 + 18;
6191 h192 = rp->hash;
6192 r192 = rp->rand;
6193 h256 = NULL;
6194 r256 = NULL;
6195 }
6196 } else {
6197 struct hci_rp_read_local_oob_ext_data *rp;
6198
6199 if (skb->len != sizeof(*rp)) {
6200 status = MGMT_STATUS_FAILED;
6201 eir_len = 0;
6202 } else {
6203 status = MGMT_STATUS_SUCCESS;
6204 rp = (void *)skb->data;
6205
6206 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6207 eir_len = 5 + 18 + 18;
6208 h192 = NULL;
6209 r192 = NULL;
6210 } else {
6211 eir_len = 5 + 18 + 18 + 18 + 18;
6212 h192 = rp->hash192;
6213 r192 = rp->rand192;
6214 }
6215
6216 h256 = rp->hash256;
6217 r256 = rp->rand256;
6218 }
6219 }
6220
6221 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6222 if (!mgmt_rp)
6223 goto done;
6224
6225 if (status)
6226 goto send_rsp;
6227
6228 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6229 hdev->dev_class, 3);
6230
6231 if (h192 && r192) {
6232 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6233 EIR_SSP_HASH_C192, h192, 16);
6234 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6235 EIR_SSP_RAND_R192, r192, 16);
6236 }
6237
6238 if (h256 && r256) {
6239 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6240 EIR_SSP_HASH_C256, h256, 16);
6241 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6242 EIR_SSP_RAND_R256, r256, 16);
6243 }
6244
6245send_rsp:
6246 mgmt_rp->type = mgmt_cp->type;
6247 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6248
6249 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6250 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6251 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6252 if (err < 0 || status)
6253 goto done;
6254
6255 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6256
6257 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6258 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6259 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6260done:
6261 kfree(mgmt_rp);
6262 mgmt_pending_remove(cmd);
6263}
6264
6265static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6266 struct mgmt_cp_read_local_oob_ext_data *cp)
6267{
6268 struct mgmt_pending_cmd *cmd;
6269 struct hci_request req;
6270 int err;
6271
6272 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6273 cp, sizeof(*cp));
6274 if (!cmd)
6275 return -ENOMEM;
6276
6277 hci_req_init(&req, hdev);
6278
6279 if (bredr_sc_enabled(hdev))
6280 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6281 else
6282 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6283
6284 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6285 if (err < 0) {
6286 mgmt_pending_remove(cmd);
6287 return err;
6288 }
6289
6290 return 0;
6291}
6292
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006293static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6294 void *data, u16 data_len)
6295{
6296 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6297 struct mgmt_rp_read_local_oob_ext_data *rp;
6298 size_t rp_len;
6299 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006300 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006301 int err;
6302
6303 BT_DBG("%s", hdev->name);
6304
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006305 if (hdev_is_powered(hdev)) {
6306 switch (cp->type) {
6307 case BIT(BDADDR_BREDR):
6308 status = mgmt_bredr_support(hdev);
6309 if (status)
6310 eir_len = 0;
6311 else
6312 eir_len = 5;
6313 break;
6314 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6315 status = mgmt_le_support(hdev);
6316 if (status)
6317 eir_len = 0;
6318 else
6319 eir_len = 9 + 3 + 18 + 18 + 3;
6320 break;
6321 default:
6322 status = MGMT_STATUS_INVALID_PARAMS;
6323 eir_len = 0;
6324 break;
6325 }
6326 } else {
6327 status = MGMT_STATUS_NOT_POWERED;
6328 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006329 }
6330
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006331 rp_len = sizeof(*rp) + eir_len;
6332 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006333 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006334 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006335
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006336 if (status)
6337 goto complete;
6338
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006339 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006340
6341 eir_len = 0;
6342 switch (cp->type) {
6343 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006344 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6345 err = read_local_ssp_oob_req(hdev, sk, cp);
6346 hci_dev_unlock(hdev);
6347 if (!err)
6348 goto done;
6349
6350 status = MGMT_STATUS_FAILED;
6351 goto complete;
6352 } else {
6353 eir_len = eir_append_data(rp->eir, eir_len,
6354 EIR_CLASS_OF_DEV,
6355 hdev->dev_class, 3);
6356 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006357 break;
6358 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006359 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6360 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006361 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006362 status = MGMT_STATUS_FAILED;
6363 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006364 }
6365
Marcel Holtmanne2135682015-04-02 12:00:58 -07006366 /* This should return the active RPA, but since the RPA
6367 * is only programmed on demand, it is really hard to fill
6368 * this in at the moment. For now disallow retrieving
6369 * local out-of-band data when privacy is in use.
6370 *
6371 * Returning the identity address will not help here since
6372 * pairing happens before the identity resolving key is
6373 * known and thus the connection establishment happens
6374 * based on the RPA and not the identity address.
6375 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006376 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006377 hci_dev_unlock(hdev);
6378 status = MGMT_STATUS_REJECTED;
6379 goto complete;
6380 }
6381
6382 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6383 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6384 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6385 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006386 memcpy(addr, &hdev->static_addr, 6);
6387 addr[6] = 0x01;
6388 } else {
6389 memcpy(addr, &hdev->bdaddr, 6);
6390 addr[6] = 0x00;
6391 }
6392
6393 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6394 addr, sizeof(addr));
6395
6396 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6397 role = 0x02;
6398 else
6399 role = 0x01;
6400
6401 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6402 &role, sizeof(role));
6403
Marcel Holtmann5082a592015-03-16 12:39:00 -07006404 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6405 eir_len = eir_append_data(rp->eir, eir_len,
6406 EIR_LE_SC_CONFIRM,
6407 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006408
Marcel Holtmann5082a592015-03-16 12:39:00 -07006409 eir_len = eir_append_data(rp->eir, eir_len,
6410 EIR_LE_SC_RANDOM,
6411 rand, sizeof(rand));
6412 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006413
Johan Hedbergf2252572015-11-18 12:49:20 +02006414 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006415
6416 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6417 flags |= LE_AD_NO_BREDR;
6418
6419 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6420 &flags, sizeof(flags));
6421 break;
6422 }
6423
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006424 hci_dev_unlock(hdev);
6425
Marcel Holtmann72000df2015-03-16 16:11:21 -07006426 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6427
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006428 status = MGMT_STATUS_SUCCESS;
6429
6430complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006431 rp->type = cp->type;
6432 rp->eir_len = cpu_to_le16(eir_len);
6433
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006434 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006435 status, rp, sizeof(*rp) + eir_len);
6436 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006437 goto done;
6438
6439 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6440 rp, sizeof(*rp) + eir_len,
6441 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006442
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006443done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006444 kfree(rp);
6445
6446 return err;
6447}
6448
Arman Uguray089fa8c2015-03-25 18:53:45 -07006449static u32 get_supported_adv_flags(struct hci_dev *hdev)
6450{
6451 u32 flags = 0;
6452
6453 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6454 flags |= MGMT_ADV_FLAG_DISCOV;
6455 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6456 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006457 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006458 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006459
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306460 /* In extended adv TX_POWER returned from Set Adv Param
6461 * will be always valid.
6462 */
6463 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6464 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006465 flags |= MGMT_ADV_FLAG_TX_POWER;
6466
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306467 if (ext_adv_capable(hdev)) {
6468 flags |= MGMT_ADV_FLAG_SEC_1M;
6469
6470 if (hdev->le_features[1] & HCI_LE_PHY_2M)
6471 flags |= MGMT_ADV_FLAG_SEC_2M;
6472
6473 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
6474 flags |= MGMT_ADV_FLAG_SEC_CODED;
6475 }
6476
Arman Uguray089fa8c2015-03-25 18:53:45 -07006477 return flags;
6478}
6479
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006480static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6481 void *data, u16 data_len)
6482{
6483 struct mgmt_rp_read_adv_features *rp;
6484 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006485 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006486 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006487 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006488 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006489
6490 BT_DBG("%s", hdev->name);
6491
Arman Uguray089fa8c2015-03-25 18:53:45 -07006492 if (!lmp_le_capable(hdev))
6493 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6494 MGMT_STATUS_REJECTED);
6495
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006496 hci_dev_lock(hdev);
6497
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006498 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006499 rp = kmalloc(rp_len, GFP_ATOMIC);
6500 if (!rp) {
6501 hci_dev_unlock(hdev);
6502 return -ENOMEM;
6503 }
6504
Arman Uguray089fa8c2015-03-25 18:53:45 -07006505 supported_flags = get_supported_adv_flags(hdev);
6506
6507 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006508 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6509 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006510 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006511 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006512
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006513 instance = rp->instance;
6514 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6515 *instance = adv_instance->instance;
6516 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006517 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006518
6519 hci_dev_unlock(hdev);
6520
6521 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6522 MGMT_STATUS_SUCCESS, rp, rp_len);
6523
6524 kfree(rp);
6525
6526 return err;
6527}
6528
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006529static u8 calculate_name_len(struct hci_dev *hdev)
6530{
6531 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6532
6533 return append_local_name(hdev, buf, 0);
6534}
6535
6536static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6537 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006538{
Arman Uguray4117ed72015-03-23 15:57:14 -07006539 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006540
Marcel Holtmann31a32482015-11-19 16:16:42 +01006541 if (is_adv_data) {
6542 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6543 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006544 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006545 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006546
Szymon Janc2bb368702016-09-18 12:50:05 +02006547 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006548 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006549 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006550 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006551 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006552
Szymon Janc2bb368702016-09-18 12:50:05 +02006553 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006554 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006555 }
6556
Szymon Janc2bb368702016-09-18 12:50:05 +02006557 return max_len;
6558}
6559
6560static bool flags_managed(u32 adv_flags)
6561{
6562 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6563 MGMT_ADV_FLAG_LIMITED_DISCOV |
6564 MGMT_ADV_FLAG_MANAGED_FLAGS);
6565}
6566
6567static bool tx_power_managed(u32 adv_flags)
6568{
6569 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6570}
6571
6572static bool name_managed(u32 adv_flags)
6573{
6574 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6575}
6576
6577static bool appearance_managed(u32 adv_flags)
6578{
6579 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6580}
6581
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006582static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6583 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006584{
6585 int i, cur_len;
6586 u8 max_len;
6587
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006588 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02006589
Arman Uguray4117ed72015-03-23 15:57:14 -07006590 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006591 return false;
6592
Arman Uguray4117ed72015-03-23 15:57:14 -07006593 /* Make sure that the data is correctly formatted. */
6594 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6595 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006596
Szymon Janc9c9db782016-09-18 12:50:06 +02006597 if (data[i + 1] == EIR_FLAGS &&
6598 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006599 return false;
6600
Szymon Janc2bb368702016-09-18 12:50:05 +02006601 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6602 return false;
6603
6604 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6605 return false;
6606
6607 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6608 return false;
6609
6610 if (data[i + 1] == EIR_APPEARANCE &&
6611 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006612 return false;
6613
Arman Uguray24b4f382015-03-23 15:57:12 -07006614 /* If the current field length would exceed the total data
6615 * length, then it's invalid.
6616 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006617 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006618 return false;
6619 }
6620
6621 return true;
6622}
6623
Arman Uguray24b4f382015-03-23 15:57:12 -07006624static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6625 u16 opcode)
6626{
6627 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006628 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006629 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006630 struct adv_info *adv_instance, *n;
6631 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006632
6633 BT_DBG("status %d", status);
6634
6635 hci_dev_lock(hdev);
6636
6637 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6638
Florian Grandelfffd38b2015-06-18 03:16:47 +02006639 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6640 if (!adv_instance->pending)
6641 continue;
6642
6643 if (!status) {
6644 adv_instance->pending = false;
6645 continue;
6646 }
6647
6648 instance = adv_instance->instance;
6649
6650 if (hdev->cur_adv_instance == instance)
6651 cancel_adv_timeout(hdev);
6652
6653 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006654 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006655 }
6656
6657 if (!cmd)
6658 goto unlock;
6659
Florian Grandelfffd38b2015-06-18 03:16:47 +02006660 cp = cmd->param;
6661 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006662
6663 if (status)
6664 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6665 mgmt_status(status));
6666 else
6667 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6668 mgmt_status(status), &rp, sizeof(rp));
6669
6670 mgmt_pending_remove(cmd);
6671
6672unlock:
6673 hci_dev_unlock(hdev);
6674}
6675
6676static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6677 void *data, u16 data_len)
6678{
6679 struct mgmt_cp_add_advertising *cp = data;
6680 struct mgmt_rp_add_advertising rp;
6681 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306682 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006683 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006684 u16 timeout, duration;
6685 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6686 u8 schedule_instance = 0;
6687 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006688 int err;
6689 struct mgmt_pending_cmd *cmd;
6690 struct hci_request req;
6691
6692 BT_DBG("%s", hdev->name);
6693
6694 status = mgmt_le_support(hdev);
6695 if (status)
6696 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6697 status);
6698
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006699 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6700 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6701 MGMT_STATUS_INVALID_PARAMS);
6702
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006703 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6704 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6705 MGMT_STATUS_INVALID_PARAMS);
6706
Arman Uguray24b4f382015-03-23 15:57:12 -07006707 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006708 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006709 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006710
Florian Grandelfffd38b2015-06-18 03:16:47 +02006711 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306712 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006713 */
6714 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306715 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
6716 if (flags & ~supported_flags ||
6717 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07006718 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6719 MGMT_STATUS_INVALID_PARAMS);
6720
6721 hci_dev_lock(hdev);
6722
Arman Uguray912098a2015-03-23 15:57:15 -07006723 if (timeout && !hdev_is_powered(hdev)) {
6724 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6725 MGMT_STATUS_REJECTED);
6726 goto unlock;
6727 }
6728
Arman Uguray24b4f382015-03-23 15:57:12 -07006729 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006730 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006731 pending_find(MGMT_OP_SET_LE, hdev)) {
6732 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6733 MGMT_STATUS_BUSY);
6734 goto unlock;
6735 }
6736
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006737 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
6738 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006739 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006740 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6741 MGMT_STATUS_INVALID_PARAMS);
6742 goto unlock;
6743 }
6744
Florian Grandelfffd38b2015-06-18 03:16:47 +02006745 err = hci_add_adv_instance(hdev, cp->instance, flags,
6746 cp->adv_data_len, cp->data,
6747 cp->scan_rsp_len,
6748 cp->data + cp->adv_data_len,
6749 timeout, duration);
6750 if (err < 0) {
6751 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6752 MGMT_STATUS_FAILED);
6753 goto unlock;
6754 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006755
Florian Grandelfffd38b2015-06-18 03:16:47 +02006756 /* Only trigger an advertising added event if a new instance was
6757 * actually added.
6758 */
6759 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006760 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006761
Florian Grandelfffd38b2015-06-18 03:16:47 +02006762 if (hdev->cur_adv_instance == cp->instance) {
6763 /* If the currently advertised instance is being changed then
6764 * cancel the current advertising and schedule the next
6765 * instance. If there is only one instance then the overridden
6766 * advertising data will be visible right away.
6767 */
6768 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006769
Florian Grandelfffd38b2015-06-18 03:16:47 +02006770 next_instance = hci_get_next_instance(hdev, cp->instance);
6771 if (next_instance)
6772 schedule_instance = next_instance->instance;
6773 } else if (!hdev->adv_instance_timeout) {
6774 /* Immediately advertise the new instance if no other
6775 * instance is currently being advertised.
6776 */
6777 schedule_instance = cp->instance;
6778 }
Arman Uguray912098a2015-03-23 15:57:15 -07006779
Florian Grandelfffd38b2015-06-18 03:16:47 +02006780 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6781 * there is no instance to be advertised then we have no HCI
6782 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006783 */
6784 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006785 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6786 !schedule_instance) {
6787 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006788 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6789 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6790 goto unlock;
6791 }
6792
6793 /* We're good to go, update advertising data, parameters, and start
6794 * advertising.
6795 */
6796 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6797 data_len);
6798 if (!cmd) {
6799 err = -ENOMEM;
6800 goto unlock;
6801 }
6802
6803 hci_req_init(&req, hdev);
6804
Johan Hedbergf2252572015-11-18 12:49:20 +02006805 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006806
Florian Grandelfffd38b2015-06-18 03:16:47 +02006807 if (!err)
6808 err = hci_req_run(&req, add_advertising_complete);
6809
Joseph Hwang72da7b22020-03-10 09:31:50 -07006810 if (err < 0) {
6811 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6812 MGMT_STATUS_FAILED);
Arman Uguray24b4f382015-03-23 15:57:12 -07006813 mgmt_pending_remove(cmd);
Joseph Hwang72da7b22020-03-10 09:31:50 -07006814 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006815
6816unlock:
6817 hci_dev_unlock(hdev);
6818
6819 return err;
6820}
6821
Arman Ugurayda9293352015-03-23 15:57:13 -07006822static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6823 u16 opcode)
6824{
6825 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006826 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006827 struct mgmt_rp_remove_advertising rp;
6828
6829 BT_DBG("status %d", status);
6830
6831 hci_dev_lock(hdev);
6832
6833 /* A failure status here only means that we failed to disable
6834 * advertising. Otherwise, the advertising instance has been removed,
6835 * so report success.
6836 */
6837 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6838 if (!cmd)
6839 goto unlock;
6840
Florian Grandel01948332015-06-18 03:16:48 +02006841 cp = cmd->param;
6842 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006843
6844 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6845 &rp, sizeof(rp));
6846 mgmt_pending_remove(cmd);
6847
6848unlock:
6849 hci_dev_unlock(hdev);
6850}
6851
6852static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6853 void *data, u16 data_len)
6854{
6855 struct mgmt_cp_remove_advertising *cp = data;
6856 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006857 struct mgmt_pending_cmd *cmd;
6858 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006859 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006860
6861 BT_DBG("%s", hdev->name);
6862
Arman Ugurayda9293352015-03-23 15:57:13 -07006863 hci_dev_lock(hdev);
6864
Johan Hedberg952497b2015-06-18 21:05:31 +03006865 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006866 err = mgmt_cmd_status(sk, hdev->id,
6867 MGMT_OP_REMOVE_ADVERTISING,
6868 MGMT_STATUS_INVALID_PARAMS);
6869 goto unlock;
6870 }
6871
Arman Ugurayda9293352015-03-23 15:57:13 -07006872 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6873 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6874 pending_find(MGMT_OP_SET_LE, hdev)) {
6875 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6876 MGMT_STATUS_BUSY);
6877 goto unlock;
6878 }
6879
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006880 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006881 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6882 MGMT_STATUS_INVALID_PARAMS);
6883 goto unlock;
6884 }
6885
Florian Grandel01948332015-06-18 03:16:48 +02006886 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006887
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006888 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006889
Florian Grandel01948332015-06-18 03:16:48 +02006890 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006891 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006892
Florian Grandel01948332015-06-18 03:16:48 +02006893 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6894 * flag is set or the device isn't powered then we have no HCI
6895 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006896 */
Florian Grandel01948332015-06-18 03:16:48 +02006897 if (skb_queue_empty(&req.cmd_q) ||
6898 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006899 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05306900 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02006901 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006902 err = mgmt_cmd_complete(sk, hdev->id,
6903 MGMT_OP_REMOVE_ADVERTISING,
6904 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6905 goto unlock;
6906 }
6907
6908 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6909 data_len);
6910 if (!cmd) {
6911 err = -ENOMEM;
6912 goto unlock;
6913 }
6914
Arman Ugurayda9293352015-03-23 15:57:13 -07006915 err = hci_req_run(&req, remove_advertising_complete);
6916 if (err < 0)
6917 mgmt_pending_remove(cmd);
6918
6919unlock:
6920 hci_dev_unlock(hdev);
6921
6922 return err;
6923}
6924
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006925static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6926 void *data, u16 data_len)
6927{
6928 struct mgmt_cp_get_adv_size_info *cp = data;
6929 struct mgmt_rp_get_adv_size_info rp;
6930 u32 flags, supported_flags;
6931 int err;
6932
6933 BT_DBG("%s", hdev->name);
6934
6935 if (!lmp_le_capable(hdev))
6936 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6937 MGMT_STATUS_REJECTED);
6938
6939 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6940 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6941 MGMT_STATUS_INVALID_PARAMS);
6942
6943 flags = __le32_to_cpu(cp->flags);
6944
6945 /* The current implementation only supports a subset of the specified
6946 * flags.
6947 */
6948 supported_flags = get_supported_adv_flags(hdev);
6949 if (flags & ~supported_flags)
6950 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6951 MGMT_STATUS_INVALID_PARAMS);
6952
6953 rp.instance = cp->instance;
6954 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006955 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
6956 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006957
6958 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6959 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6960
6961 return err;
6962}
6963
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006964static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006965 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006966 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006967 HCI_MGMT_NO_HDEV |
6968 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006969 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006970 HCI_MGMT_NO_HDEV |
6971 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006972 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006973 HCI_MGMT_NO_HDEV |
6974 HCI_MGMT_UNTRUSTED },
6975 { read_controller_info, MGMT_READ_INFO_SIZE,
6976 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006977 { set_powered, MGMT_SETTING_SIZE },
6978 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6979 { set_connectable, MGMT_SETTING_SIZE },
6980 { set_fast_connectable, MGMT_SETTING_SIZE },
6981 { set_bondable, MGMT_SETTING_SIZE },
6982 { set_link_security, MGMT_SETTING_SIZE },
6983 { set_ssp, MGMT_SETTING_SIZE },
6984 { set_hs, MGMT_SETTING_SIZE },
6985 { set_le, MGMT_SETTING_SIZE },
6986 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6987 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6988 { add_uuid, MGMT_ADD_UUID_SIZE },
6989 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006990 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6991 HCI_MGMT_VAR_LEN },
6992 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6993 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006994 { disconnect, MGMT_DISCONNECT_SIZE },
6995 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6996 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6997 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6998 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6999 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7000 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7001 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7002 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7003 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7004 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7005 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007006 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7007 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7008 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007009 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7010 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7011 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7012 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7013 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7014 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7015 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7016 { set_advertising, MGMT_SETTING_SIZE },
7017 { set_bredr, MGMT_SETTING_SIZE },
7018 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7019 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7020 { set_secure_conn, MGMT_SETTING_SIZE },
7021 { set_debug_keys, MGMT_SETTING_SIZE },
7022 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007023 { load_irks, MGMT_LOAD_IRKS_SIZE,
7024 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007025 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7026 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7027 { add_device, MGMT_ADD_DEVICE_SIZE },
7028 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007029 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7030 HCI_MGMT_VAR_LEN },
7031 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007032 HCI_MGMT_NO_HDEV |
7033 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007034 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007035 HCI_MGMT_UNCONFIGURED |
7036 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007037 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7038 HCI_MGMT_UNCONFIGURED },
7039 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7040 HCI_MGMT_UNCONFIGURED },
7041 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7042 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007043 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007044 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007045 HCI_MGMT_NO_HDEV |
7046 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007047 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007048 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7049 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007050 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01007051 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02007052 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007053 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
7054 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02007055 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05307056 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05307057 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Alain Michaud600a8742020-01-07 00:43:17 +00007058 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE,
7059 HCI_MGMT_VAR_LEN },
Alain Michaud00bce3f2020-03-05 16:14:59 +00007060 { set_wideband_speech, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007061};
7062
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007063void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007064{
Marcel Holtmannced85542015-03-14 19:27:56 -07007065 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007066
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007067 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7068 return;
7069
Marcel Holtmannf9207332015-03-14 19:27:55 -07007070 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007071 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007072 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7073 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7074 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007075 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007076 } else {
7077 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7078 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007079 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007080 }
7081 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007082 case HCI_AMP:
7083 ev.type = 0x02;
7084 break;
7085 default:
7086 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007087 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007088
7089 ev.bus = hdev->bus;
7090
7091 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7092 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007093}
7094
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007095void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007096{
Marcel Holtmannced85542015-03-14 19:27:56 -07007097 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007098 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007099
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007100 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7101 return;
7102
Marcel Holtmannf9207332015-03-14 19:27:55 -07007103 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02007104 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07007105 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007106
Marcel Holtmannf9207332015-03-14 19:27:55 -07007107 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7108 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7109 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007110 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007111 } else {
7112 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7113 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007114 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007115 }
7116 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007117 case HCI_AMP:
7118 ev.type = 0x02;
7119 break;
7120 default:
7121 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007122 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007123
7124 ev.bus = hdev->bus;
7125
7126 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7127 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007128}
7129
Andre Guedes6046dc32014-02-26 20:21:51 -03007130/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007131static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03007132{
7133 struct hci_conn_params *p;
7134
7135 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007136 /* Needed for AUTO_OFF case where might not "really"
7137 * have been powered off.
7138 */
7139 list_del_init(&p->action);
7140
7141 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007142 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007143 case HCI_AUTO_CONN_ALWAYS:
7144 list_add(&p->action, &hdev->pend_le_conns);
7145 break;
7146 case HCI_AUTO_CONN_REPORT:
7147 list_add(&p->action, &hdev->pend_le_reports);
7148 break;
7149 default:
7150 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007151 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007152 }
7153}
7154
Johan Hedberg2ff13892015-11-25 16:15:44 +02007155void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007156{
7157 struct cmd_lookup match = { NULL, hdev };
7158
Johan Hedberg2ff13892015-11-25 16:15:44 +02007159 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007160
Johan Hedberg2ff13892015-11-25 16:15:44 +02007161 hci_dev_lock(hdev);
7162
7163 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007164 restart_le_actions(hdev);
7165 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007166 }
7167
Johan Hedberg229ab392013-03-15 17:06:53 -05007168 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7169
7170 new_settings(hdev, match.sk);
7171
Johan Hedberg229ab392013-03-15 17:06:53 -05007172 if (match.sk)
7173 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007174
7175 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007176}
7177
Johan Hedberg2ff13892015-11-25 16:15:44 +02007178void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007179{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007180 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007181 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007182
Johan Hedberg229ab392013-03-15 17:06:53 -05007183 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007184
7185 /* If the power off is because of hdev unregistration let
7186 * use the appropriate INVALID_INDEX status. Otherwise use
7187 * NOT_POWERED. We cover both scenarios here since later in
7188 * mgmt_index_removed() any hci_conn callbacks will have already
7189 * been triggered, potentially causing misleading DISCONNECTED
7190 * status responses.
7191 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007192 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007193 status = MGMT_STATUS_INVALID_INDEX;
7194 else
7195 status = MGMT_STATUS_NOT_POWERED;
7196
7197 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007198
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007199 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007200 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7201 zero_cod, sizeof(zero_cod),
7202 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007203 ext_info_changed(hdev, NULL);
7204 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007205
Johan Hedberg2ff13892015-11-25 16:15:44 +02007206 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007207
7208 if (match.sk)
7209 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007210}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007211
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007212void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007213{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007214 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007215 u8 status;
7216
Johan Hedberg333ae952015-03-17 13:48:47 +02007217 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007218 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007219 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007220
7221 if (err == -ERFKILL)
7222 status = MGMT_STATUS_RFKILLED;
7223 else
7224 status = MGMT_STATUS_FAILED;
7225
Johan Hedberga69e8372015-03-06 21:08:53 +02007226 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007227
7228 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007229}
7230
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007231void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7232 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007233{
Johan Hedberg86742e12011-11-07 23:13:38 +02007234 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007235
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007236 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007237
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007238 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007239 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007240 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007241 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007242 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007243 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007244
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007245 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007246}
Johan Hedbergf7520542011-01-20 12:34:39 +02007247
Johan Hedbergd7b25452014-05-23 13:19:53 +03007248static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7249{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007250 switch (ltk->type) {
7251 case SMP_LTK:
7252 case SMP_LTK_SLAVE:
7253 if (ltk->authenticated)
7254 return MGMT_LTK_AUTHENTICATED;
7255 return MGMT_LTK_UNAUTHENTICATED;
7256 case SMP_LTK_P256:
7257 if (ltk->authenticated)
7258 return MGMT_LTK_P256_AUTH;
7259 return MGMT_LTK_P256_UNAUTH;
7260 case SMP_LTK_P256_DEBUG:
7261 return MGMT_LTK_P256_DEBUG;
7262 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007263
7264 return MGMT_LTK_UNAUTHENTICATED;
7265}
7266
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007267void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007268{
7269 struct mgmt_ev_new_long_term_key ev;
7270
7271 memset(&ev, 0, sizeof(ev));
7272
Marcel Holtmann5192d302014-02-19 17:11:58 -08007273 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007274 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007275 * to store long term keys. Their addresses will change the
7276 * next time around.
7277 *
7278 * Only when a remote device provides an identity address
7279 * make sure the long term key is stored. If the remote
7280 * identity is known, the long term keys are internally
7281 * mapped to the identity address. So allow static random
7282 * and public addresses here.
7283 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007284 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7285 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7286 ev.store_hint = 0x00;
7287 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007288 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007289
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007290 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007291 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007292 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007293 ev.key.enc_size = key->enc_size;
7294 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007295 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007296
Johan Hedberg2ceba532014-06-16 19:25:16 +03007297 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007298 ev.key.master = 1;
7299
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007300 /* Make sure we copy only the significant bytes based on the
7301 * encryption key size, and set the rest of the value to zeroes.
7302 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007303 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007304 memset(ev.key.val + key->enc_size, 0,
7305 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007306
Marcel Holtmann083368f2013-10-15 14:26:29 -07007307 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007308}
7309
Johan Hedbergcad20c22015-10-12 13:36:19 +02007310void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007311{
7312 struct mgmt_ev_new_irk ev;
7313
7314 memset(&ev, 0, sizeof(ev));
7315
Johan Hedbergcad20c22015-10-12 13:36:19 +02007316 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007317
Johan Hedberg95fbac82014-02-19 15:18:31 +02007318 bacpy(&ev.rpa, &irk->rpa);
7319 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7320 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7321 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7322
7323 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7324}
7325
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007326void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7327 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007328{
7329 struct mgmt_ev_new_csrk ev;
7330
7331 memset(&ev, 0, sizeof(ev));
7332
7333 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007334 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007335 * to store signature resolving keys. Their addresses will change
7336 * the next time around.
7337 *
7338 * Only when a remote device provides an identity address
7339 * make sure the signature resolving key is stored. So allow
7340 * static random and public addresses here.
7341 */
7342 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7343 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7344 ev.store_hint = 0x00;
7345 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007346 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007347
7348 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7349 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007350 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007351 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7352
7353 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7354}
7355
Andre Guedesffb5a8272014-07-01 18:10:11 -03007356void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007357 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7358 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007359{
7360 struct mgmt_ev_new_conn_param ev;
7361
Johan Hedbergc103aea2014-07-02 17:37:34 +03007362 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7363 return;
7364
Andre Guedesffb5a8272014-07-01 18:10:11 -03007365 memset(&ev, 0, sizeof(ev));
7366 bacpy(&ev.addr.bdaddr, bdaddr);
7367 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007368 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007369 ev.min_interval = cpu_to_le16(min_interval);
7370 ev.max_interval = cpu_to_le16(max_interval);
7371 ev.latency = cpu_to_le16(latency);
7372 ev.timeout = cpu_to_le16(timeout);
7373
7374 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7375}
7376
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007377void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7378 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007379{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007380 char buf[512];
7381 struct mgmt_ev_device_connected *ev = (void *) buf;
7382 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007383
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007384 bacpy(&ev->addr.bdaddr, &conn->dst);
7385 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007386
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007387 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007388
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007389 /* We must ensure that the EIR Data fields are ordered and
7390 * unique. Keep it simple for now and avoid the problem by not
7391 * adding any BR/EDR data to the LE adv.
7392 */
7393 if (conn->le_adv_data_len > 0) {
7394 memcpy(&ev->eir[eir_len],
7395 conn->le_adv_data, conn->le_adv_data_len);
7396 eir_len = conn->le_adv_data_len;
7397 } else {
7398 if (name_len > 0)
7399 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7400 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007401
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007402 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007403 eir_len = eir_append_data(ev->eir, eir_len,
7404 EIR_CLASS_OF_DEV,
7405 conn->dev_class, 3);
7406 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007407
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007408 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007409
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007410 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7411 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007412}
7413
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007414static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007415{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007416 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007417
Johan Hedbergf5818c22014-12-05 13:36:02 +02007418 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007419
7420 *sk = cmd->sk;
7421 sock_hold(*sk);
7422
Johan Hedberga664b5b2011-02-19 12:06:02 -03007423 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007424}
7425
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007426static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007427{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007428 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007429 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007430
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007431 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7432
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007433 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007434 mgmt_pending_remove(cmd);
7435}
7436
Johan Hedberg84c61d92014-08-01 11:13:30 +03007437bool mgmt_powering_down(struct hci_dev *hdev)
7438{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007439 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007440 struct mgmt_mode *cp;
7441
Johan Hedberg333ae952015-03-17 13:48:47 +02007442 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007443 if (!cmd)
7444 return false;
7445
7446 cp = cmd->param;
7447 if (!cp->val)
7448 return true;
7449
7450 return false;
7451}
7452
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007453void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007454 u8 link_type, u8 addr_type, u8 reason,
7455 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007456{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007457 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007458 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007459
Johan Hedberg84c61d92014-08-01 11:13:30 +03007460 /* The connection is still in hci_conn_hash so test for 1
7461 * instead of 0 to know if this is the last one.
7462 */
7463 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7464 cancel_delayed_work(&hdev->power_off);
7465 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007466 }
7467
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007468 if (!mgmt_connected)
7469 return;
7470
Andre Guedes57eb7762013-10-30 19:01:41 -03007471 if (link_type != ACL_LINK && link_type != LE_LINK)
7472 return;
7473
Johan Hedberg744cf192011-11-08 20:40:14 +02007474 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007475
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007476 bacpy(&ev.addr.bdaddr, bdaddr);
7477 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7478 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007479
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007480 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007481
7482 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007483 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007484
Johan Hedberg124f6e32012-02-09 13:50:12 +02007485 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007486 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007487}
7488
Marcel Holtmann78929242013-10-06 23:55:47 -07007489void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7490 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007491{
Andre Guedes3655bba2013-10-30 19:01:40 -03007492 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7493 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007494 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007495
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007496 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7497 hdev);
7498
Johan Hedberg333ae952015-03-17 13:48:47 +02007499 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007500 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007501 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007502
Andre Guedes3655bba2013-10-30 19:01:40 -03007503 cp = cmd->param;
7504
7505 if (bacmp(bdaddr, &cp->addr.bdaddr))
7506 return;
7507
7508 if (cp->addr.type != bdaddr_type)
7509 return;
7510
Johan Hedbergf5818c22014-12-05 13:36:02 +02007511 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007512 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007513}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007514
Marcel Holtmann445608d2013-10-06 23:55:48 -07007515void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7516 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007517{
7518 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007519
Johan Hedberg84c61d92014-08-01 11:13:30 +03007520 /* The connection is still in hci_conn_hash so test for 1
7521 * instead of 0 to know if this is the last one.
7522 */
7523 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7524 cancel_delayed_work(&hdev->power_off);
7525 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007526 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007527
Johan Hedberg4c659c32011-11-07 23:13:39 +02007528 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007529 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007530 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007531
Marcel Holtmann445608d2013-10-06 23:55:48 -07007532 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007533}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007534
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007535void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007536{
7537 struct mgmt_ev_pin_code_request ev;
7538
Johan Hedbergd8457692012-02-17 14:24:57 +02007539 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007540 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007541 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007542
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007543 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007544}
7545
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007546void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7547 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007548{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007549 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007550
Johan Hedberg333ae952015-03-17 13:48:47 +02007551 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007552 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007553 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007554
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007555 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007556 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007557}
7558
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007559void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7560 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007561{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007562 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007563
Johan Hedberg333ae952015-03-17 13:48:47 +02007564 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007565 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007566 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007567
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007568 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007569 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007570}
Johan Hedberga5c29682011-02-19 12:05:57 -03007571
Johan Hedberg744cf192011-11-08 20:40:14 +02007572int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007573 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007574 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007575{
7576 struct mgmt_ev_user_confirm_request ev;
7577
Johan Hedberg744cf192011-11-08 20:40:14 +02007578 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007579
Johan Hedberg272d90d2012-02-09 15:26:12 +02007580 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007581 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007582 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007583 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007584
Johan Hedberg744cf192011-11-08 20:40:14 +02007585 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007586 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007587}
7588
Johan Hedberg272d90d2012-02-09 15:26:12 +02007589int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007590 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007591{
7592 struct mgmt_ev_user_passkey_request ev;
7593
7594 BT_DBG("%s", hdev->name);
7595
Johan Hedberg272d90d2012-02-09 15:26:12 +02007596 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007597 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007598
7599 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007600 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007601}
7602
Brian Gix0df4c182011-11-16 13:53:13 -08007603static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007604 u8 link_type, u8 addr_type, u8 status,
7605 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007606{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007607 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007608
Johan Hedberg333ae952015-03-17 13:48:47 +02007609 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007610 if (!cmd)
7611 return -ENOENT;
7612
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007613 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007614 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007615
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007616 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007617}
7618
Johan Hedberg744cf192011-11-08 20:40:14 +02007619int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007620 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007621{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007622 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007623 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007624}
7625
Johan Hedberg272d90d2012-02-09 15:26:12 +02007626int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007627 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007628{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007629 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007630 status,
7631 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007632}
Johan Hedberg2a611692011-02-19 12:06:00 -03007633
Brian Gix604086b2011-11-23 08:28:33 -08007634int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007635 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007636{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007637 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007638 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007639}
7640
Johan Hedberg272d90d2012-02-09 15:26:12 +02007641int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007642 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007643{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007644 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007645 status,
7646 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007647}
7648
Johan Hedberg92a25252012-09-06 18:39:26 +03007649int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7650 u8 link_type, u8 addr_type, u32 passkey,
7651 u8 entered)
7652{
7653 struct mgmt_ev_passkey_notify ev;
7654
7655 BT_DBG("%s", hdev->name);
7656
7657 bacpy(&ev.addr.bdaddr, bdaddr);
7658 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7659 ev.passkey = __cpu_to_le32(passkey);
7660 ev.entered = entered;
7661
7662 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7663}
7664
Johan Hedberge1e930f2014-09-08 17:09:49 -07007665void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007666{
7667 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007668 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007669 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007670
Johan Hedberge1e930f2014-09-08 17:09:49 -07007671 bacpy(&ev.addr.bdaddr, &conn->dst);
7672 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7673 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007674
Johan Hedberge1e930f2014-09-08 17:09:49 -07007675 cmd = find_pairing(conn);
7676
7677 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7678 cmd ? cmd->sk : NULL);
7679
Johan Hedberga511b352014-12-11 21:45:45 +02007680 if (cmd) {
7681 cmd->cmd_complete(cmd, status);
7682 mgmt_pending_remove(cmd);
7683 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007684}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007685
Marcel Holtmann464996a2013-10-15 14:26:24 -07007686void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007687{
7688 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007689 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007690
7691 if (status) {
7692 u8 mgmt_err = mgmt_status(status);
7693 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007694 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007695 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007696 }
7697
Marcel Holtmann464996a2013-10-15 14:26:24 -07007698 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007699 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007700 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007701 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007702
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007703 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007704 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007705
Johan Hedberg47990ea2012-02-22 11:58:37 +02007706 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007707 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007708
7709 if (match.sk)
7710 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007711}
7712
Johan Hedberg890ea892013-03-15 17:06:52 -05007713static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007714{
Johan Hedberg890ea892013-03-15 17:06:52 -05007715 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007716 struct hci_cp_write_eir cp;
7717
Johan Hedberg976eb202012-10-24 21:12:01 +03007718 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007719 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007720
Johan Hedbergc80da272012-02-22 15:38:48 +02007721 memset(hdev->eir, 0, sizeof(hdev->eir));
7722
Johan Hedbergcacaf522012-02-21 00:52:42 +02007723 memset(&cp, 0, sizeof(cp));
7724
Johan Hedberg890ea892013-03-15 17:06:52 -05007725 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007726}
7727
Marcel Holtmann3e248562013-10-15 14:26:25 -07007728void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007729{
7730 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007731 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007732 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007733
7734 if (status) {
7735 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007736
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007737 if (enable && hci_dev_test_and_clear_flag(hdev,
7738 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007739 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007740 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007741 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007742
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007743 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7744 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007745 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007746 }
7747
7748 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007749 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007750 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007751 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007752 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007753 changed = hci_dev_test_and_clear_flag(hdev,
7754 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007755 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007756 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007757 }
7758
7759 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7760
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007761 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007762 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007763
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007764 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007765 sock_put(match.sk);
7766
Johan Hedberg890ea892013-03-15 17:06:52 -05007767 hci_req_init(&req, hdev);
7768
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007769 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7770 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007771 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7772 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007773 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007774 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007775 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007776 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007777
7778 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007779}
7780
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007781static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007782{
7783 struct cmd_lookup *match = data;
7784
Johan Hedberg90e70452012-02-23 23:09:40 +02007785 if (match->sk == NULL) {
7786 match->sk = cmd->sk;
7787 sock_hold(match->sk);
7788 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007789}
7790
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007791void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7792 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007793{
Johan Hedberg90e70452012-02-23 23:09:40 +02007794 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007795
Johan Hedberg92da6092013-03-15 17:06:55 -05007796 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7797 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7798 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007799
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007800 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007801 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7802 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007803 ext_info_changed(hdev, NULL);
7804 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007805
7806 if (match.sk)
7807 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007808}
7809
Marcel Holtmann7667da32013-10-15 14:26:27 -07007810void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007811{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007812 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007813 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007814
Johan Hedberg13928972013-03-15 17:07:00 -05007815 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007816 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007817
7818 memset(&ev, 0, sizeof(ev));
7819 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007820 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007821
Johan Hedberg333ae952015-03-17 13:48:47 +02007822 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007823 if (!cmd) {
7824 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007825
Johan Hedberg13928972013-03-15 17:07:00 -05007826 /* If this is a HCI command related to powering on the
7827 * HCI dev don't send any mgmt signals.
7828 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007829 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007830 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007831 }
7832
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007833 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7834 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007835 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007836}
Szymon Jancc35938b2011-03-22 13:12:21 +01007837
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007838static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7839{
7840 int i;
7841
7842 for (i = 0; i < uuid_count; i++) {
7843 if (!memcmp(uuid, uuids[i], 16))
7844 return true;
7845 }
7846
7847 return false;
7848}
7849
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007850static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7851{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007852 u16 parsed = 0;
7853
7854 while (parsed < eir_len) {
7855 u8 field_len = eir[0];
7856 u8 uuid[16];
7857 int i;
7858
7859 if (field_len == 0)
7860 break;
7861
7862 if (eir_len - parsed < field_len + 1)
7863 break;
7864
7865 switch (eir[1]) {
7866 case EIR_UUID16_ALL:
7867 case EIR_UUID16_SOME:
7868 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007869 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007870 uuid[13] = eir[i + 3];
7871 uuid[12] = eir[i + 2];
7872 if (has_uuid(uuid, uuid_count, uuids))
7873 return true;
7874 }
7875 break;
7876 case EIR_UUID32_ALL:
7877 case EIR_UUID32_SOME:
7878 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007879 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007880 uuid[15] = eir[i + 5];
7881 uuid[14] = eir[i + 4];
7882 uuid[13] = eir[i + 3];
7883 uuid[12] = eir[i + 2];
7884 if (has_uuid(uuid, uuid_count, uuids))
7885 return true;
7886 }
7887 break;
7888 case EIR_UUID128_ALL:
7889 case EIR_UUID128_SOME:
7890 for (i = 0; i + 17 <= field_len; i += 16) {
7891 memcpy(uuid, eir + i + 2, 16);
7892 if (has_uuid(uuid, uuid_count, uuids))
7893 return true;
7894 }
7895 break;
7896 }
7897
7898 parsed += field_len + 1;
7899 eir += field_len + 1;
7900 }
7901
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007902 return false;
7903}
7904
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007905static void restart_le_scan(struct hci_dev *hdev)
7906{
7907 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007908 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007909 return;
7910
7911 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7912 hdev->discovery.scan_start +
7913 hdev->discovery.scan_duration))
7914 return;
7915
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007916 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007917 DISCOV_LE_RESTART_DELAY);
7918}
7919
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007920static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7921 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7922{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007923 /* If a RSSI threshold has been specified, and
7924 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7925 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7926 * is set, let it through for further processing, as we might need to
7927 * restart the scan.
7928 *
7929 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7930 * the results are also dropped.
7931 */
7932 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7933 (rssi == HCI_RSSI_INVALID ||
7934 (rssi < hdev->discovery.rssi &&
7935 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7936 return false;
7937
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007938 if (hdev->discovery.uuid_count != 0) {
7939 /* If a list of UUIDs is provided in filter, results with no
7940 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007941 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007942 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7943 hdev->discovery.uuids) &&
7944 !eir_has_uuids(scan_rsp, scan_rsp_len,
7945 hdev->discovery.uuid_count,
7946 hdev->discovery.uuids))
7947 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007948 }
7949
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007950 /* If duplicate filtering does not report RSSI changes, then restart
7951 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007952 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007953 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7954 restart_le_scan(hdev);
7955
7956 /* Validate RSSI value against the RSSI threshold once more. */
7957 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7958 rssi < hdev->discovery.rssi)
7959 return false;
7960 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007961
7962 return true;
7963}
7964
Marcel Holtmann901801b2013-10-06 23:55:51 -07007965void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007966 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7967 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007968{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007969 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007970 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007971 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007972
Johan Hedberg75ce2082014-07-02 22:42:01 +03007973 /* Don't send events for a non-kernel initiated discovery. With
7974 * LE one exception is if we have pend_le_reports > 0 in which
7975 * case we're doing passive scanning and want these events.
7976 */
7977 if (!hci_discovery_active(hdev)) {
7978 if (link_type == ACL_LINK)
7979 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007980 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007981 return;
7982 }
Andre Guedes12602d02013-04-30 15:29:40 -03007983
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007984 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007985 /* We are using service discovery */
7986 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7987 scan_rsp_len))
7988 return;
7989 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007990
Johan Hedberg78b781c2016-01-05 13:19:32 +02007991 if (hdev->discovery.limited) {
7992 /* Check for limited discoverable bit */
7993 if (dev_class) {
7994 if (!(dev_class[1] & 0x20))
7995 return;
7996 } else {
7997 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7998 if (!flags || !(flags[0] & LE_AD_LIMITED))
7999 return;
8000 }
8001 }
8002
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008003 /* Make sure that the buffer is big enough. The 5 extra bytes
8004 * are for the potential CoD field.
8005 */
8006 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008007 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008008
Johan Hedberg1dc06092012-01-15 21:01:23 +02008009 memset(buf, 0, sizeof(buf));
8010
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008011 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8012 * RSSI value was reported as 0 when not available. This behavior
8013 * is kept when using device discovery. This is required for full
8014 * backwards compatibility with the API.
8015 *
8016 * However when using service discovery, the value 127 will be
8017 * returned when the RSSI is not available.
8018 */
Szymon Janc91200e92015-01-22 16:57:05 +01008019 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8020 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008021 rssi = 0;
8022
Johan Hedberg841c5642014-07-07 12:45:54 +03008023 bacpy(&ev->addr.bdaddr, bdaddr);
8024 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008025 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008026 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008027
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008028 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008029 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008030 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008031
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02008032 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
8033 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02008034 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008035 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008036
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008037 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008038 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008039 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008040
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008041 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8042 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008043
Marcel Holtmann901801b2013-10-06 23:55:51 -07008044 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008045}
Johan Hedberga88a9652011-03-30 13:18:12 +03008046
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008047void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8048 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008049{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008050 struct mgmt_ev_device_found *ev;
8051 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8052 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008053
Johan Hedbergb644ba32012-01-17 21:48:47 +02008054 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008055
Johan Hedbergb644ba32012-01-17 21:48:47 +02008056 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008057
Johan Hedbergb644ba32012-01-17 21:48:47 +02008058 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008059 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008060 ev->rssi = rssi;
8061
8062 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008063 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008064
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008065 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008066
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008067 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008068}
Johan Hedberg314b2382011-04-27 10:29:57 -04008069
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008070void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008071{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008072 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008073
Andre Guedes343fb142011-11-22 17:14:19 -03008074 BT_DBG("%s discovering %u", hdev->name, discovering);
8075
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008076 memset(&ev, 0, sizeof(ev));
8077 ev.type = hdev->discovery.type;
8078 ev.discovering = discovering;
8079
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008080 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008081}
Antti Julku5e762442011-08-25 16:48:02 +03008082
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008083static struct hci_mgmt_chan chan = {
8084 .channel = HCI_CHANNEL_CONTROL,
8085 .handler_count = ARRAY_SIZE(mgmt_handlers),
8086 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008087 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008088};
8089
8090int mgmt_init(void)
8091{
8092 return hci_mgmt_chan_register(&chan);
8093}
8094
8095void mgmt_exit(void)
8096{
8097 hci_mgmt_chan_unregister(&chan);
8098}