blob: 150114e33b20f22c6da3bc25d4a2b9a7ffa5f81e [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
Szymon Janc33102302016-09-18 12:50:07 +020041#define MGMT_REVISION 14
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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200109};
110
111static const u16 mgmt_events[] = {
112 MGMT_EV_CONTROLLER_ERROR,
113 MGMT_EV_INDEX_ADDED,
114 MGMT_EV_INDEX_REMOVED,
115 MGMT_EV_NEW_SETTINGS,
116 MGMT_EV_CLASS_OF_DEV_CHANGED,
117 MGMT_EV_LOCAL_NAME_CHANGED,
118 MGMT_EV_NEW_LINK_KEY,
119 MGMT_EV_NEW_LONG_TERM_KEY,
120 MGMT_EV_DEVICE_CONNECTED,
121 MGMT_EV_DEVICE_DISCONNECTED,
122 MGMT_EV_CONNECT_FAILED,
123 MGMT_EV_PIN_CODE_REQUEST,
124 MGMT_EV_USER_CONFIRM_REQUEST,
125 MGMT_EV_USER_PASSKEY_REQUEST,
126 MGMT_EV_AUTH_FAILED,
127 MGMT_EV_DEVICE_FOUND,
128 MGMT_EV_DISCOVERING,
129 MGMT_EV_DEVICE_BLOCKED,
130 MGMT_EV_DEVICE_UNBLOCKED,
131 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300132 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800133 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700134 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200135 MGMT_EV_DEVICE_ADDED,
136 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300137 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200138 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200139 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200140 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700141 MGMT_EV_EXT_INDEX_ADDED,
142 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700143 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700144 MGMT_EV_ADVERTISING_ADDED,
145 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200146 MGMT_EV_EXT_INFO_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200147};
148
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700149static const u16 mgmt_untrusted_commands[] = {
150 MGMT_OP_READ_INDEX_LIST,
151 MGMT_OP_READ_INFO,
152 MGMT_OP_READ_UNCONF_INDEX_LIST,
153 MGMT_OP_READ_CONFIG_INFO,
154 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200155 MGMT_OP_READ_EXT_INFO,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700156};
157
158static const u16 mgmt_untrusted_events[] = {
159 MGMT_EV_INDEX_ADDED,
160 MGMT_EV_INDEX_REMOVED,
161 MGMT_EV_NEW_SETTINGS,
162 MGMT_EV_CLASS_OF_DEV_CHANGED,
163 MGMT_EV_LOCAL_NAME_CHANGED,
164 MGMT_EV_UNCONF_INDEX_ADDED,
165 MGMT_EV_UNCONF_INDEX_REMOVED,
166 MGMT_EV_NEW_CONFIG_OPTIONS,
167 MGMT_EV_EXT_INDEX_ADDED,
168 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200169 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700170};
171
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800172#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200173
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200174#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
175 "\x00\x00\x00\x00\x00\x00\x00\x00"
176
Johan Hedbergca69b792011-11-11 18:10:00 +0200177/* HCI to MGMT error code conversion table */
178static u8 mgmt_status_table[] = {
179 MGMT_STATUS_SUCCESS,
180 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
181 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
182 MGMT_STATUS_FAILED, /* Hardware Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
184 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200185 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200186 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
187 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
188 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
189 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
190 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
191 MGMT_STATUS_BUSY, /* Command Disallowed */
192 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
193 MGMT_STATUS_REJECTED, /* Rejected Security */
194 MGMT_STATUS_REJECTED, /* Rejected Personal */
195 MGMT_STATUS_TIMEOUT, /* Host Timeout */
196 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
197 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
198 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
199 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
200 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
201 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
202 MGMT_STATUS_BUSY, /* Repeated Attempts */
203 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
204 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
206 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
207 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
208 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
209 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
210 MGMT_STATUS_FAILED, /* Unspecified Error */
211 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
212 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
213 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
214 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
215 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
216 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
217 MGMT_STATUS_FAILED, /* Unit Link Key Used */
218 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
219 MGMT_STATUS_TIMEOUT, /* Instant Passed */
220 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
221 MGMT_STATUS_FAILED, /* Transaction Collision */
222 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
223 MGMT_STATUS_REJECTED, /* QoS Rejected */
224 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
225 MGMT_STATUS_REJECTED, /* Insufficient Security */
226 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
227 MGMT_STATUS_BUSY, /* Role Switch Pending */
228 MGMT_STATUS_FAILED, /* Slot Violation */
229 MGMT_STATUS_FAILED, /* Role Switch Failed */
230 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
231 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
232 MGMT_STATUS_BUSY, /* Host Busy Pairing */
233 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
234 MGMT_STATUS_BUSY, /* Controller Busy */
235 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
236 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
237 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
238 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
239 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
240};
241
242static u8 mgmt_status(u8 hci_status)
243{
244 if (hci_status < ARRAY_SIZE(mgmt_status_table))
245 return mgmt_status_table[hci_status];
246
247 return MGMT_STATUS_FAILED;
248}
249
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700250static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
251 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700252{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700253 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
254 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700255}
256
Marcel Holtmann72000df2015-03-16 16:11:21 -0700257static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
258 u16 len, int flag, struct sock *skip_sk)
259{
260 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
261 flag, skip_sk);
262}
263
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200264static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
265 struct sock *skip_sk)
266{
267 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700268 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200269}
270
Johan Hedberg85813a72015-10-21 18:02:59 +0300271static u8 le_addr_type(u8 mgmt_addr_type)
272{
273 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
274 return ADDR_LE_DEV_PUBLIC;
275 else
276 return ADDR_LE_DEV_RANDOM;
277}
278
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200279void mgmt_fill_version_info(void *ver)
280{
281 struct mgmt_rp_read_version *rp = ver;
282
283 rp->version = MGMT_VERSION;
284 rp->revision = cpu_to_le16(MGMT_REVISION);
285}
286
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300287static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
288 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200289{
290 struct mgmt_rp_read_version rp;
291
292 BT_DBG("sock %p", sk);
293
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200294 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200295
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200296 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
297 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200298}
299
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300300static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
301 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302{
303 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305 size_t rp_size;
306 int i, err;
307
308 BT_DBG("sock %p", sk);
309
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700310 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
311 num_commands = ARRAY_SIZE(mgmt_commands);
312 num_events = ARRAY_SIZE(mgmt_events);
313 } else {
314 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
315 num_events = ARRAY_SIZE(mgmt_untrusted_events);
316 }
317
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200318 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
319
320 rp = kmalloc(rp_size, GFP_KERNEL);
321 if (!rp)
322 return -ENOMEM;
323
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700324 rp->num_commands = cpu_to_le16(num_commands);
325 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200326
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700327 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
328 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200329
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700330 for (i = 0; i < num_commands; i++, opcode++)
331 put_unaligned_le16(mgmt_commands[i], opcode);
332
333 for (i = 0; i < num_events; i++, opcode++)
334 put_unaligned_le16(mgmt_events[i], opcode);
335 } else {
336 __le16 *opcode = rp->opcodes;
337
338 for (i = 0; i < num_commands; i++, opcode++)
339 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
340
341 for (i = 0; i < num_events; i++, opcode++)
342 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
343 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200344
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200345 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
346 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200347 kfree(rp);
348
349 return err;
350}
351
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300352static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
353 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200356 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300359 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
361 BT_DBG("sock %p", sk);
362
363 read_lock(&hci_dev_list_lock);
364
365 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300366 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200367 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700368 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700369 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 }
371
Johan Hedberga38528f2011-01-22 06:46:43 +0200372 rp_len = sizeof(*rp) + (2 * count);
373 rp = kmalloc(rp_len, GFP_ATOMIC);
374 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100375 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200376 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100377 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200378
Johan Hedberg476e44c2012-10-19 20:10:46 +0300379 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200380 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700381 if (hci_dev_test_flag(d, HCI_SETUP) ||
382 hci_dev_test_flag(d, HCI_CONFIG) ||
383 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 /* Devices marked as raw-only are neither configured
387 * nor unconfigured controllers.
388 */
389 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700390 continue;
391
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200392 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700393 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700394 rp->index[count++] = cpu_to_le16(d->id);
395 BT_DBG("Added hci%u", d->id);
396 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200397 }
398
Johan Hedberg476e44c2012-10-19 20:10:46 +0300399 rp->num_controllers = cpu_to_le16(count);
400 rp_len = sizeof(*rp) + (2 * count);
401
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200402 read_unlock(&hci_dev_list_lock);
403
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200404 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
405 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200406
Johan Hedberga38528f2011-01-22 06:46:43 +0200407 kfree(rp);
408
409 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200410}
411
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200412static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
413 void *data, u16 data_len)
414{
415 struct mgmt_rp_read_unconf_index_list *rp;
416 struct hci_dev *d;
417 size_t rp_len;
418 u16 count;
419 int err;
420
421 BT_DBG("sock %p", sk);
422
423 read_lock(&hci_dev_list_lock);
424
425 count = 0;
426 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200427 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700428 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200429 count++;
430 }
431
432 rp_len = sizeof(*rp) + (2 * count);
433 rp = kmalloc(rp_len, GFP_ATOMIC);
434 if (!rp) {
435 read_unlock(&hci_dev_list_lock);
436 return -ENOMEM;
437 }
438
439 count = 0;
440 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700441 if (hci_dev_test_flag(d, HCI_SETUP) ||
442 hci_dev_test_flag(d, HCI_CONFIG) ||
443 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200444 continue;
445
446 /* Devices marked as raw-only are neither configured
447 * nor unconfigured controllers.
448 */
449 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
450 continue;
451
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200452 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700453 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200454 rp->index[count++] = cpu_to_le16(d->id);
455 BT_DBG("Added hci%u", d->id);
456 }
457 }
458
459 rp->num_controllers = cpu_to_le16(count);
460 rp_len = sizeof(*rp) + (2 * count);
461
462 read_unlock(&hci_dev_list_lock);
463
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200464 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
465 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200466
467 kfree(rp);
468
469 return err;
470}
471
Marcel Holtmann96f14742015-03-14 19:27:57 -0700472static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
473 void *data, u16 data_len)
474{
475 struct mgmt_rp_read_ext_index_list *rp;
476 struct hci_dev *d;
Marcel Holtmann96f14742015-03-14 19:27:57 -0700477 u16 count;
478 int err;
479
480 BT_DBG("sock %p", sk);
481
482 read_lock(&hci_dev_list_lock);
483
484 count = 0;
485 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200486 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700487 count++;
488 }
489
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600490 rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700491 if (!rp) {
492 read_unlock(&hci_dev_list_lock);
493 return -ENOMEM;
494 }
495
496 count = 0;
497 list_for_each_entry(d, &hci_dev_list, list) {
498 if (hci_dev_test_flag(d, HCI_SETUP) ||
499 hci_dev_test_flag(d, HCI_CONFIG) ||
500 hci_dev_test_flag(d, HCI_USER_CHANNEL))
501 continue;
502
503 /* Devices marked as raw-only are neither configured
504 * nor unconfigured controllers.
505 */
506 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
507 continue;
508
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200509 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700510 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
511 rp->entry[count].type = 0x01;
512 else
513 rp->entry[count].type = 0x00;
514 } else if (d->dev_type == HCI_AMP) {
515 rp->entry[count].type = 0x02;
516 } else {
517 continue;
518 }
519
520 rp->entry[count].bus = d->bus;
521 rp->entry[count++].index = cpu_to_le16(d->id);
522 BT_DBG("Added hci%u", d->id);
523 }
524
525 rp->num_controllers = cpu_to_le16(count);
Marcel Holtmann96f14742015-03-14 19:27:57 -0700526
527 read_unlock(&hci_dev_list_lock);
528
529 /* If this command is called at least once, then all the
530 * default index and unconfigured index events are disabled
531 * and from now on only extended index events are used.
532 */
533 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
534 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
535 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
536
537 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
Gustavo A. R. Silva4a67e5d2019-02-25 13:11:37 -0600538 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp,
539 struct_size(rp, entry, count));
Marcel Holtmann96f14742015-03-14 19:27:57 -0700540
541 kfree(rp);
542
543 return err;
544}
545
Marcel Holtmanndbece372014-07-04 18:11:55 +0200546static bool is_configured(struct hci_dev *hdev)
547{
548 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700549 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200550 return false;
551
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800552 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
553 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmanndbece372014-07-04 18:11:55 +0200554 !bacmp(&hdev->public_addr, BDADDR_ANY))
555 return false;
556
557 return true;
558}
559
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200560static __le32 get_missing_options(struct hci_dev *hdev)
561{
562 u32 options = 0;
563
Marcel Holtmanndbece372014-07-04 18:11:55 +0200564 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700565 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200566 options |= MGMT_OPTION_EXTERNAL_CONFIG;
567
Matthias Kaehlcke7a0e5b12019-02-19 12:05:57 -0800568 if ((test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
569 test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) &&
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200570 !bacmp(&hdev->public_addr, BDADDR_ANY))
571 options |= MGMT_OPTION_PUBLIC_ADDRESS;
572
573 return cpu_to_le32(options);
574}
575
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576static int new_options(struct hci_dev *hdev, struct sock *skip)
577{
578 __le32 options = get_missing_options(hdev);
579
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200580 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
581 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200582}
583
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
585{
586 __le32 options = get_missing_options(hdev);
587
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200588 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
589 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200590}
591
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200592static int read_config_info(struct sock *sk, struct hci_dev *hdev,
593 void *data, u16 data_len)
594{
595 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200596 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200597
598 BT_DBG("sock %p %s", sk, hdev->name);
599
600 hci_dev_lock(hdev);
601
602 memset(&rp, 0, sizeof(rp));
603 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200604
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200605 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
606 options |= MGMT_OPTION_EXTERNAL_CONFIG;
607
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200608 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200609 options |= MGMT_OPTION_PUBLIC_ADDRESS;
610
611 rp.supported_options = cpu_to_le32(options);
612 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200613
614 hci_dev_unlock(hdev);
615
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200616 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
617 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200618}
619
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530620static u32 get_supported_phys(struct hci_dev *hdev)
621{
622 u32 supported_phys = 0;
623
624 if (lmp_bredr_capable(hdev)) {
625 supported_phys |= MGMT_PHY_BR_1M_1SLOT;
626
627 if (hdev->features[0][0] & LMP_3SLOT)
628 supported_phys |= MGMT_PHY_BR_1M_3SLOT;
629
630 if (hdev->features[0][0] & LMP_5SLOT)
631 supported_phys |= MGMT_PHY_BR_1M_5SLOT;
632
633 if (lmp_edr_2m_capable(hdev)) {
634 supported_phys |= MGMT_PHY_EDR_2M_1SLOT;
635
636 if (lmp_edr_3slot_capable(hdev))
637 supported_phys |= MGMT_PHY_EDR_2M_3SLOT;
638
639 if (lmp_edr_5slot_capable(hdev))
640 supported_phys |= MGMT_PHY_EDR_2M_5SLOT;
641
642 if (lmp_edr_3m_capable(hdev)) {
643 supported_phys |= MGMT_PHY_EDR_3M_1SLOT;
644
645 if (lmp_edr_3slot_capable(hdev))
646 supported_phys |= MGMT_PHY_EDR_3M_3SLOT;
647
648 if (lmp_edr_5slot_capable(hdev))
649 supported_phys |= MGMT_PHY_EDR_3M_5SLOT;
650 }
651 }
652 }
653
654 if (lmp_le_capable(hdev)) {
655 supported_phys |= MGMT_PHY_LE_1M_TX;
656 supported_phys |= MGMT_PHY_LE_1M_RX;
657
658 if (hdev->le_features[1] & HCI_LE_PHY_2M) {
659 supported_phys |= MGMT_PHY_LE_2M_TX;
660 supported_phys |= MGMT_PHY_LE_2M_RX;
661 }
662
663 if (hdev->le_features[1] & HCI_LE_PHY_CODED) {
664 supported_phys |= MGMT_PHY_LE_CODED_TX;
665 supported_phys |= MGMT_PHY_LE_CODED_RX;
666 }
667 }
668
669 return supported_phys;
670}
671
672static u32 get_selected_phys(struct hci_dev *hdev)
673{
674 u32 selected_phys = 0;
675
676 if (lmp_bredr_capable(hdev)) {
677 selected_phys |= MGMT_PHY_BR_1M_1SLOT;
678
679 if (hdev->pkt_type & (HCI_DM3 | HCI_DH3))
680 selected_phys |= MGMT_PHY_BR_1M_3SLOT;
681
682 if (hdev->pkt_type & (HCI_DM5 | HCI_DH5))
683 selected_phys |= MGMT_PHY_BR_1M_5SLOT;
684
685 if (lmp_edr_2m_capable(hdev)) {
686 if (!(hdev->pkt_type & HCI_2DH1))
687 selected_phys |= MGMT_PHY_EDR_2M_1SLOT;
688
689 if (lmp_edr_3slot_capable(hdev) &&
690 !(hdev->pkt_type & HCI_2DH3))
691 selected_phys |= MGMT_PHY_EDR_2M_3SLOT;
692
693 if (lmp_edr_5slot_capable(hdev) &&
694 !(hdev->pkt_type & HCI_2DH5))
695 selected_phys |= MGMT_PHY_EDR_2M_5SLOT;
696
697 if (lmp_edr_3m_capable(hdev)) {
698 if (!(hdev->pkt_type & HCI_3DH1))
699 selected_phys |= MGMT_PHY_EDR_3M_1SLOT;
700
701 if (lmp_edr_3slot_capable(hdev) &&
702 !(hdev->pkt_type & HCI_3DH3))
703 selected_phys |= MGMT_PHY_EDR_3M_3SLOT;
704
705 if (lmp_edr_5slot_capable(hdev) &&
706 !(hdev->pkt_type & HCI_3DH5))
707 selected_phys |= MGMT_PHY_EDR_3M_5SLOT;
708 }
709 }
710 }
711
712 if (lmp_le_capable(hdev)) {
713 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_1M)
714 selected_phys |= MGMT_PHY_LE_1M_TX;
715
716 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_1M)
717 selected_phys |= MGMT_PHY_LE_1M_RX;
718
719 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_2M)
720 selected_phys |= MGMT_PHY_LE_2M_TX;
721
722 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_2M)
723 selected_phys |= MGMT_PHY_LE_2M_RX;
724
725 if (hdev->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
726 selected_phys |= MGMT_PHY_LE_CODED_TX;
727
728 if (hdev->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
729 selected_phys |= MGMT_PHY_LE_CODED_RX;
730 }
731
732 return selected_phys;
733}
734
735static u32 get_configurable_phys(struct hci_dev *hdev)
736{
737 return (get_supported_phys(hdev) & ~MGMT_PHY_BR_1M_1SLOT &
738 ~MGMT_PHY_LE_1M_TX & ~MGMT_PHY_LE_1M_RX);
739}
740
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200742{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200743 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200744
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200745 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300746 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800747 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300748 settings |= MGMT_SETTING_CONNECTABLE;
749 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200750
Andre Guedesed3fa312012-07-24 15:03:46 -0300751 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500752 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
753 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200754 settings |= MGMT_SETTING_BREDR;
755 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700756
757 if (lmp_ssp_capable(hdev)) {
758 settings |= MGMT_SETTING_SSP;
759 settings |= MGMT_SETTING_HS;
760 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800761
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800762 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800763 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700764 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100765
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300766 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200767 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300768 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300769 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200770 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800771 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300772 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200773
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200774 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
775 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200776 settings |= MGMT_SETTING_CONFIGURATION;
777
Jaganath Kanakkassery62446912018-07-19 17:09:34 +0530778 settings |= MGMT_SETTING_PHY_CONFIGURATION;
779
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200780 return settings;
781}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200782
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200783static u32 get_current_settings(struct hci_dev *hdev)
784{
785 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200786
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200787 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100788 settings |= MGMT_SETTING_POWERED;
789
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700790 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791 settings |= MGMT_SETTING_CONNECTABLE;
792
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700793 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500794 settings |= MGMT_SETTING_FAST_CONNECTABLE;
795
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700796 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200797 settings |= MGMT_SETTING_DISCOVERABLE;
798
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700799 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300800 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200801
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700802 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200803 settings |= MGMT_SETTING_BREDR;
804
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700805 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200806 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200807
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700808 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200809 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200810
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700811 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200812 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200813
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700814 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200815 settings |= MGMT_SETTING_HS;
816
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700817 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300818 settings |= MGMT_SETTING_ADVERTISING;
819
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700820 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800821 settings |= MGMT_SETTING_SECURE_CONN;
822
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700823 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800824 settings |= MGMT_SETTING_DEBUG_KEYS;
825
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700826 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200827 settings |= MGMT_SETTING_PRIVACY;
828
Marcel Holtmann93690c22015-03-06 10:11:21 -0800829 /* The current setting for static address has two purposes. The
830 * first is to indicate if the static address will be used and
831 * the second is to indicate if it is actually set.
832 *
833 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700834 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800835 * address is actually used decides if the flag is set or not.
836 *
837 * For single mode LE only controllers and dual-mode controllers
838 * with BR/EDR disabled, the existence of the static address will
839 * be evaluated.
840 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700841 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700842 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800843 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
844 if (bacmp(&hdev->static_addr, BDADDR_ANY))
845 settings |= MGMT_SETTING_STATIC_ADDRESS;
846 }
847
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200848 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200849}
850
Johan Hedberg333ae952015-03-17 13:48:47 +0200851static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
852{
853 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
854}
855
Johan Hedberg333ae952015-03-17 13:48:47 +0200856static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
857 struct hci_dev *hdev,
858 const void *data)
859{
860 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
861}
862
Johan Hedbergf2252572015-11-18 12:49:20 +0200863u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300864{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200865 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300866
867 /* If there's a pending mgmt command the flags will not yet have
868 * their final values, so check for this first.
869 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200870 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300871 if (cmd) {
872 struct mgmt_mode *cp = cmd->param;
873 if (cp->val == 0x01)
874 return LE_AD_GENERAL;
875 else if (cp->val == 0x02)
876 return LE_AD_LIMITED;
877 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700878 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300879 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700880 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300881 return LE_AD_GENERAL;
882 }
883
884 return 0;
885}
886
Johan Hedbergf2252572015-11-18 12:49:20 +0200887bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700888{
889 struct mgmt_pending_cmd *cmd;
890
891 /* If there's a pending mgmt command the flag will not yet have
892 * it's final value, so check for this first.
893 */
894 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
895 if (cmd) {
896 struct mgmt_mode *cp = cmd->param;
897
898 return cp->val;
899 }
900
901 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
902}
903
Johan Hedberg7d785252011-12-15 00:47:39 +0200904static void service_cache_off(struct work_struct *work)
905{
906 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300907 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500908 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200909
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700910 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200911 return;
912
Johan Hedberg890ea892013-03-15 17:06:52 -0500913 hci_req_init(&req, hdev);
914
Johan Hedberg7d785252011-12-15 00:47:39 +0200915 hci_dev_lock(hdev);
916
Johan Hedbergb1a89172015-11-25 16:15:42 +0200917 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200918 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200919
920 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500921
922 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200923}
924
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200925static void rpa_expired(struct work_struct *work)
926{
927 struct hci_dev *hdev = container_of(work, struct hci_dev,
928 rpa_expired.work);
929 struct hci_request req;
930
931 BT_DBG("");
932
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700933 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200934
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700935 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200936 return;
937
938 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200939 * controller happens in the hci_req_enable_advertising()
940 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200941 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200942 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530943 if (ext_adv_capable(hdev))
944 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
945 else
946 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200947 hci_req_run(&req, NULL);
948}
949
Johan Hedberg6a919082012-02-28 06:17:26 +0200950static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200951{
Marcel Holtmann238be782015-03-13 02:11:06 -0700952 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200953 return;
954
Johan Hedberg4f87da82012-03-02 19:55:56 +0200955 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200956 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200957
Johan Hedberg4f87da82012-03-02 19:55:56 +0200958 /* Non-mgmt controlled devices get this bit set
959 * implicitly so that pairing works for them, however
960 * for mgmt we require user-space to explicitly enable
961 * it
962 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700963 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200964}
965
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200966static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300967 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200968{
969 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200970
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200971 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200972
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300973 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200974
Johan Hedberg03811012010-12-08 00:21:06 +0200975 memset(&rp, 0, sizeof(rp));
976
Johan Hedberg03811012010-12-08 00:21:06 +0200977 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200978
979 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200980 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200981
982 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
983 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
984
985 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200986
987 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200988 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200989
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300990 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200991
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200992 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
993 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200994}
995
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +0200996static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
997{
998 u16 eir_len = 0;
999 size_t name_len;
1000
1001 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1002 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1003 hdev->dev_class, 3);
1004
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001005 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1006 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1007 hdev->appearance);
1008
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001009 name_len = strlen(hdev->dev_name);
1010 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1011 hdev->dev_name, name_len);
1012
1013 name_len = strlen(hdev->short_name);
1014 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1015 hdev->short_name, name_len);
1016
1017 return eir_len;
1018}
1019
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001020static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1021 void *data, u16 data_len)
1022{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001023 char buf[512];
1024 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001025 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001026
1027 BT_DBG("sock %p %s", sk, hdev->name);
1028
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001029 memset(&buf, 0, sizeof(buf));
1030
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001031 hci_dev_lock(hdev);
1032
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001033 bacpy(&rp->bdaddr, &hdev->bdaddr);
1034
1035 rp->version = hdev->hci_ver;
1036 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1037
1038 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1039 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001040
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001041
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001042 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001043 rp->eir_len = cpu_to_le16(eir_len);
1044
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001045 hci_dev_unlock(hdev);
1046
1047 /* If this command is called at least once, then the events
1048 * for class of device and local name changes are disabled
1049 * and only the new extended controller information event
1050 * is used.
1051 */
1052 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1053 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1054 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1055
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001056 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1057 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001058}
1059
1060static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1061{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001062 char buf[512];
1063 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1064 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001065
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001066 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001067
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001068 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1069 ev->eir_len = cpu_to_le16(eir_len);
1070
1071 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1072 sizeof(*ev) + eir_len,
1073 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001074}
1075
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001076static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001077{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001078 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001079
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001080 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1081 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001082}
1083
Marcel Holtmann1904a852015-01-11 13:50:44 -08001084static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001085{
1086 BT_DBG("%s status 0x%02x", hdev->name, status);
1087
Johan Hedberga3172b72014-02-28 09:33:44 +02001088 if (hci_conn_count(hdev) == 0) {
1089 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001090 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001091 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001092}
1093
Johan Hedbergf2252572015-11-18 12:49:20 +02001094void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001095{
1096 struct mgmt_ev_advertising_added ev;
1097
1098 ev.instance = instance;
1099
1100 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1101}
1102
Johan Hedbergf2252572015-11-18 12:49:20 +02001103void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1104 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001105{
1106 struct mgmt_ev_advertising_removed ev;
1107
1108 ev.instance = instance;
1109
1110 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1111}
1112
Florian Grandel7816b822015-06-18 03:16:45 +02001113static void cancel_adv_timeout(struct hci_dev *hdev)
1114{
1115 if (hdev->adv_instance_timeout) {
1116 hdev->adv_instance_timeout = 0;
1117 cancel_delayed_work(&hdev->adv_instance_expire);
1118 }
1119}
1120
Johan Hedberg8b064a32014-02-24 14:52:22 +02001121static int clean_up_hci_state(struct hci_dev *hdev)
1122{
1123 struct hci_request req;
1124 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001125 bool discov_stopped;
1126 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001127
1128 hci_req_init(&req, hdev);
1129
1130 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1131 test_bit(HCI_PSCAN, &hdev->flags)) {
1132 u8 scan = 0x00;
1133 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1134 }
1135
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001136 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001137
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001138 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001139 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001140
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001141 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001142
1143 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001144 /* 0x15 == Terminated due to Power Off */
1145 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001146 }
1147
Johan Hedberg23a48092014-07-08 16:05:06 +03001148 err = hci_req_run(&req, clean_up_hci_complete);
1149 if (!err && discov_stopped)
1150 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1151
1152 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001153}
1154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001155static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001156 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001157{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001158 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001159 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001160 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001162 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001163
Johan Hedberga7e80f22013-01-09 16:05:19 +02001164 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001165 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1166 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001168 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001169
Johan Hedberg333ae952015-03-17 13:48:47 +02001170 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001171 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1172 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001173 goto failed;
1174 }
1175
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001176 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001177 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001178 goto failed;
1179 }
1180
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001181 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1182 if (!cmd) {
1183 err = -ENOMEM;
1184 goto failed;
1185 }
1186
Johan Hedberg8b064a32014-02-24 14:52:22 +02001187 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001188 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001189 err = 0;
1190 } else {
1191 /* Disconnect connections, stop scans, etc */
1192 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001193 if (!err)
1194 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1195 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
Johan Hedberg8b064a32014-02-24 14:52:22 +02001197 /* ENODATA means there were no HCI commands queued */
1198 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001199 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001200 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1201 err = 0;
1202 }
1203 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001204
1205failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001206 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207 return err;
1208}
1209
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001210static int new_settings(struct hci_dev *hdev, struct sock *skip)
1211{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001212 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001213
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001214 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1215 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001216}
1217
Johan Hedberg91a668b2014-07-09 13:28:26 +03001218int mgmt_new_settings(struct hci_dev *hdev)
1219{
1220 return new_settings(hdev, NULL);
1221}
1222
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001223struct cmd_lookup {
1224 struct sock *sk;
1225 struct hci_dev *hdev;
1226 u8 mgmt_status;
1227};
1228
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001229static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001230{
1231 struct cmd_lookup *match = data;
1232
1233 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1234
1235 list_del(&cmd->list);
1236
1237 if (match->sk == NULL) {
1238 match->sk = cmd->sk;
1239 sock_hold(match->sk);
1240 }
1241
1242 mgmt_pending_free(cmd);
1243}
1244
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001245static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001246{
1247 u8 *status = data;
1248
Johan Hedberga69e8372015-03-06 21:08:53 +02001249 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001250 mgmt_pending_remove(cmd);
1251}
1252
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001253static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001254{
1255 if (cmd->cmd_complete) {
1256 u8 *status = data;
1257
1258 cmd->cmd_complete(cmd, *status);
1259 mgmt_pending_remove(cmd);
1260
1261 return;
1262 }
1263
1264 cmd_status_rsp(cmd, data);
1265}
1266
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001267static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001268{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001269 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1270 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001271}
1272
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001273static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001274{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001275 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1276 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001277}
1278
Johan Hedberge6fe7982013-10-02 15:45:22 +03001279static u8 mgmt_bredr_support(struct hci_dev *hdev)
1280{
1281 if (!lmp_bredr_capable(hdev))
1282 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001283 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001284 return MGMT_STATUS_REJECTED;
1285 else
1286 return MGMT_STATUS_SUCCESS;
1287}
1288
1289static u8 mgmt_le_support(struct hci_dev *hdev)
1290{
1291 if (!lmp_le_capable(hdev))
1292 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001293 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001294 return MGMT_STATUS_REJECTED;
1295 else
1296 return MGMT_STATUS_SUCCESS;
1297}
1298
Johan Hedbergaed1a882015-11-22 17:24:44 +03001299void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001300{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001301 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001302
1303 BT_DBG("status 0x%02x", status);
1304
1305 hci_dev_lock(hdev);
1306
Johan Hedberg333ae952015-03-17 13:48:47 +02001307 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001308 if (!cmd)
1309 goto unlock;
1310
1311 if (status) {
1312 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001313 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001314 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001315 goto remove_cmd;
1316 }
1317
Johan Hedbergaed1a882015-11-22 17:24:44 +03001318 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1319 hdev->discov_timeout > 0) {
1320 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1321 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001322 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001323
1324 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001325 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001326
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001327remove_cmd:
1328 mgmt_pending_remove(cmd);
1329
1330unlock:
1331 hci_dev_unlock(hdev);
1332}
1333
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001334static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001335 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001336{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001337 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001338 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001339 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001340 int err;
1341
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001343
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001344 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1345 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001346 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1347 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001348
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001349 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001350 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1351 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001352
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001353 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001354
1355 /* Disabling discoverable requires that no timeout is set,
1356 * and enabling limited discoverable requires a timeout.
1357 */
1358 if ((cp->val == 0x00 && timeout > 0) ||
1359 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001360 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001363 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001364
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001365 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001366 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1367 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001368 goto failed;
1369 }
1370
Johan Hedberg333ae952015-03-17 13:48:47 +02001371 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1372 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001373 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1374 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001375 goto failed;
1376 }
1377
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001378 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001379 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1380 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001381 goto failed;
1382 }
1383
1384 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001385 bool changed = false;
1386
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001387 /* Setting limited discoverable when powered off is
1388 * not a valid operation since it requires a timeout
1389 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1390 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001391 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001392 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001393 changed = true;
1394 }
1395
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001396 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001397 if (err < 0)
1398 goto failed;
1399
1400 if (changed)
1401 err = new_settings(hdev, sk);
1402
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001403 goto failed;
1404 }
1405
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001406 /* If the current mode is the same, then just update the timeout
1407 * value with the new value. And if only the timeout gets updated,
1408 * then no need for any HCI transactions.
1409 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001410 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1411 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1412 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001413 cancel_delayed_work(&hdev->discov_off);
1414 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001415
Marcel Holtmann36261542013-10-15 08:28:51 -07001416 if (cp->val && hdev->discov_timeout > 0) {
1417 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001418 queue_delayed_work(hdev->req_workqueue,
1419 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001420 }
1421
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001422 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001423 goto failed;
1424 }
1425
1426 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1427 if (!cmd) {
1428 err = -ENOMEM;
1429 goto failed;
1430 }
1431
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001432 /* Cancel any potential discoverable timeout that might be
1433 * still active and store new timeout value. The arming of
1434 * the timeout happens in the complete handler.
1435 */
1436 cancel_delayed_work(&hdev->discov_off);
1437 hdev->discov_timeout = timeout;
1438
Johan Hedbergaed1a882015-11-22 17:24:44 +03001439 if (cp->val)
1440 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1441 else
1442 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1443
Johan Hedbergb456f872013-10-19 23:38:22 +03001444 /* Limited discoverable mode */
1445 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001446 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001447 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001448 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001449
Johan Hedbergaed1a882015-11-22 17:24:44 +03001450 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1451 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001452
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001453failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001454 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001455 return err;
1456}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001457
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001458void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001459{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001460 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001461
1462 BT_DBG("status 0x%02x", status);
1463
1464 hci_dev_lock(hdev);
1465
Johan Hedberg333ae952015-03-17 13:48:47 +02001466 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001467 if (!cmd)
1468 goto unlock;
1469
Johan Hedberg37438c12013-10-14 16:20:05 +03001470 if (status) {
1471 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001472 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001473 goto remove_cmd;
1474 }
1475
Johan Hedberg2b76f452013-03-15 17:07:04 -05001476 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001477 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001478
Johan Hedberg37438c12013-10-14 16:20:05 +03001479remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001480 mgmt_pending_remove(cmd);
1481
1482unlock:
1483 hci_dev_unlock(hdev);
1484}
1485
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001486static int set_connectable_update_settings(struct hci_dev *hdev,
1487 struct sock *sk, u8 val)
1488{
1489 bool changed = false;
1490 int err;
1491
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001492 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001493 changed = true;
1494
1495 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001496 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001497 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001498 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1499 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001500 }
1501
1502 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1503 if (err < 0)
1504 return err;
1505
Johan Hedberg562064e2014-07-08 16:35:34 +03001506 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001507 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001508 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001509 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001510 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001511
1512 return 0;
1513}
1514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001515static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001516 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001517{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001518 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001519 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001520 int err;
1521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001522 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001523
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001524 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1525 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001526 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1527 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001528
Johan Hedberga7e80f22013-01-09 16:05:19 +02001529 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001530 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1531 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001532
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001533 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001534
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001535 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001536 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001537 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001538 }
1539
Johan Hedberg333ae952015-03-17 13:48:47 +02001540 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1541 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001542 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1543 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001544 goto failed;
1545 }
1546
Johan Hedberg73f22f62010-12-29 16:00:25 +02001547 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1548 if (!cmd) {
1549 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001550 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001551 }
1552
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001553 if (cp->val) {
1554 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1555 } else {
1556 if (hdev->discov_timeout > 0)
1557 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001558
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001559 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1560 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1561 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001562 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001563
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001564 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1565 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001566
1567failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001568 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001569 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001570}
1571
Johan Hedbergb2939472014-07-30 09:22:23 +03001572static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001573 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001574{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001575 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001576 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001577 int err;
1578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001579 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001580
Johan Hedberga7e80f22013-01-09 16:05:19 +02001581 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001582 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1583 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001584
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001585 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001586
1587 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001588 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001589 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001590 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001591
Johan Hedbergb2939472014-07-30 09:22:23 +03001592 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001593 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001594 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001595
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001596 if (changed) {
1597 /* In limited privacy mode the change of bondable mode
1598 * may affect the local advertising address.
1599 */
1600 if (hdev_is_powered(hdev) &&
1601 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1602 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1603 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1604 queue_work(hdev->req_workqueue,
1605 &hdev->discoverable_update);
1606
Marcel Holtmann55594352013-10-06 16:11:57 -07001607 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001608 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001609
Marcel Holtmann55594352013-10-06 16:11:57 -07001610unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001611 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001612 return err;
1613}
1614
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001615static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1616 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001617{
1618 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001619 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001620 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001621 int err;
1622
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001623 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001624
Johan Hedberge6fe7982013-10-02 15:45:22 +03001625 status = mgmt_bredr_support(hdev);
1626 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001627 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1628 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001629
Johan Hedberga7e80f22013-01-09 16:05:19 +02001630 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001631 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001633
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001634 hci_dev_lock(hdev);
1635
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001636 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001637 bool changed = false;
1638
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001639 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001640 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001641 changed = true;
1642 }
1643
1644 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1645 if (err < 0)
1646 goto failed;
1647
1648 if (changed)
1649 err = new_settings(hdev, sk);
1650
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001651 goto failed;
1652 }
1653
Johan Hedberg333ae952015-03-17 13:48:47 +02001654 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001655 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1656 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001657 goto failed;
1658 }
1659
1660 val = !!cp->val;
1661
1662 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1663 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1664 goto failed;
1665 }
1666
1667 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1668 if (!cmd) {
1669 err = -ENOMEM;
1670 goto failed;
1671 }
1672
1673 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1674 if (err < 0) {
1675 mgmt_pending_remove(cmd);
1676 goto failed;
1677 }
1678
1679failed:
1680 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001681 return err;
1682}
1683
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001684static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001685{
1686 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001687 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001688 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001689 int err;
1690
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001691 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001692
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001693 status = mgmt_bredr_support(hdev);
1694 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001695 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001696
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001697 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001698 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1699 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001700
Johan Hedberga7e80f22013-01-09 16:05:19 +02001701 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001702 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1703 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001704
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001705 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001706
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001707 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001708 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001709
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001710 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001711 changed = !hci_dev_test_and_set_flag(hdev,
1712 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001713 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001714 changed = hci_dev_test_and_clear_flag(hdev,
1715 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001716 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001717 changed = hci_dev_test_and_clear_flag(hdev,
1718 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001719 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001720 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001721 }
1722
1723 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1724 if (err < 0)
1725 goto failed;
1726
1727 if (changed)
1728 err = new_settings(hdev, sk);
1729
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001730 goto failed;
1731 }
1732
Johan Hedberg333ae952015-03-17 13:48:47 +02001733 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001734 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1735 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001736 goto failed;
1737 }
1738
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001739 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001740 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1741 goto failed;
1742 }
1743
1744 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1745 if (!cmd) {
1746 err = -ENOMEM;
1747 goto failed;
1748 }
1749
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001750 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001751 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1752 sizeof(cp->val), &cp->val);
1753
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001754 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001755 if (err < 0) {
1756 mgmt_pending_remove(cmd);
1757 goto failed;
1758 }
1759
1760failed:
1761 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001762 return err;
1763}
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001766{
1767 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001768 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001769 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001770 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001772 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001773
Johan Hedberge6fe7982013-10-02 15:45:22 +03001774 status = mgmt_bredr_support(hdev);
1775 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001776 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001777
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001778 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001779 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1780 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001781
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001782 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001783 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1784 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001785
Johan Hedberga7e80f22013-01-09 16:05:19 +02001786 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001787 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1788 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001789
Marcel Holtmannee392692013-10-01 22:59:23 -07001790 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001791
Johan Hedberg333ae952015-03-17 13:48:47 +02001792 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001793 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1794 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001795 goto unlock;
1796 }
1797
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001798 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001799 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001800 } else {
1801 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001802 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1803 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001804 goto unlock;
1805 }
1806
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001807 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001808 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001809
1810 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1811 if (err < 0)
1812 goto unlock;
1813
1814 if (changed)
1815 err = new_settings(hdev, sk);
1816
1817unlock:
1818 hci_dev_unlock(hdev);
1819 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001820}
1821
Marcel Holtmann1904a852015-01-11 13:50:44 -08001822static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001823{
1824 struct cmd_lookup match = { NULL, hdev };
1825
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301826 hci_dev_lock(hdev);
1827
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001828 if (status) {
1829 u8 mgmt_err = mgmt_status(status);
1830
1831 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1832 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301833 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001834 }
1835
1836 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1837
1838 new_settings(hdev, match.sk);
1839
1840 if (match.sk)
1841 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001842
1843 /* Make sure the controller has a good default for
1844 * advertising data. Restrict the update to when LE
1845 * has actually been enabled. During power on, the
1846 * update in powered_update_hci will take care of it.
1847 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001848 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001849 struct hci_request req;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001850 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301851 if (ext_adv_capable(hdev)) {
1852 int err;
1853
1854 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1855 if (!err)
1856 __hci_req_update_scan_rsp_data(&req, 0x00);
1857 } else {
1858 __hci_req_update_adv_data(&req, 0x00);
1859 __hci_req_update_scan_rsp_data(&req, 0x00);
1860 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001861 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001862 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001863 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301864
1865unlock:
1866 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001867}
1868
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001870{
1871 struct mgmt_mode *cp = data;
1872 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001873 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001874 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001875 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001876 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001877
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001878 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001879
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001880 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001881 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1882 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001883
Johan Hedberga7e80f22013-01-09 16:05:19 +02001884 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001885 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1886 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001887
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001888 /* Bluetooth single mode LE only controllers or dual-mode
1889 * controllers configured as LE only devices, do not allow
1890 * switching LE off. These have either LE enabled explicitly
1891 * or BR/EDR has been previously switched off.
1892 *
1893 * When trying to enable an already enabled LE, then gracefully
1894 * send a positive response. Trying to disable it however will
1895 * result into rejection.
1896 */
1897 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1898 if (cp->val == 0x01)
1899 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1900
Johan Hedberga69e8372015-03-06 21:08:53 +02001901 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1902 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001903 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001904
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001905 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001906
1907 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001908 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001909
Florian Grandel847818d2015-06-18 03:16:46 +02001910 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001911 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001912
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001913 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001914 bool changed = false;
1915
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001916 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001917 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001918 changed = true;
1919 }
1920
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001921 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001922 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001923 changed = true;
1924 }
1925
Johan Hedberg06199cf2012-02-22 16:37:11 +02001926 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1927 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001928 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001929
1930 if (changed)
1931 err = new_settings(hdev, sk);
1932
Johan Hedberg1de028c2012-02-29 19:55:35 -08001933 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001934 }
1935
Johan Hedberg333ae952015-03-17 13:48:47 +02001936 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1937 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001938 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1939 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001940 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001941 }
1942
1943 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1944 if (!cmd) {
1945 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001946 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001947 }
1948
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001949 hci_req_init(&req, hdev);
1950
Johan Hedberg06199cf2012-02-22 16:37:11 +02001951 memset(&hci_cp, 0, sizeof(hci_cp));
1952
1953 if (val) {
1954 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001955 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001956 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001957 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001958 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301959
1960 if (ext_adv_capable(hdev))
1961 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 }
1963
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001964 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1965 &hci_cp);
1966
1967 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301968 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001969 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001970
Johan Hedberg1de028c2012-02-29 19:55:35 -08001971unlock:
1972 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001973 return err;
1974}
1975
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001976/* This is a helper function to test for pending mgmt commands that can
1977 * cause CoD or EIR HCI commands. We can only allow one such pending
1978 * mgmt command at a time since otherwise we cannot easily track what
1979 * the current values are, will be, and based on that calculate if a new
1980 * HCI command needs to be sent and if yes with what value.
1981 */
1982static bool pending_eir_or_class(struct hci_dev *hdev)
1983{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001984 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001985
1986 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1987 switch (cmd->opcode) {
1988 case MGMT_OP_ADD_UUID:
1989 case MGMT_OP_REMOVE_UUID:
1990 case MGMT_OP_SET_DEV_CLASS:
1991 case MGMT_OP_SET_POWERED:
1992 return true;
1993 }
1994 }
1995
1996 return false;
1997}
1998
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001999static const u8 bluetooth_base_uuid[] = {
2000 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2001 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2002};
2003
2004static u8 get_uuid_size(const u8 *uuid)
2005{
2006 u32 val;
2007
2008 if (memcmp(uuid, bluetooth_base_uuid, 12))
2009 return 128;
2010
2011 val = get_unaligned_le32(&uuid[12]);
2012 if (val > 0xffff)
2013 return 32;
2014
2015 return 16;
2016}
2017
Johan Hedberg92da6092013-03-15 17:06:55 -05002018static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2019{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002020 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002021
2022 hci_dev_lock(hdev);
2023
Johan Hedberg333ae952015-03-17 13:48:47 +02002024 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002025 if (!cmd)
2026 goto unlock;
2027
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002028 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2029 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002030
2031 mgmt_pending_remove(cmd);
2032
2033unlock:
2034 hci_dev_unlock(hdev);
2035}
2036
Marcel Holtmann1904a852015-01-11 13:50:44 -08002037static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002038{
2039 BT_DBG("status 0x%02x", status);
2040
2041 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2042}
2043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002045{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002046 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002047 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002048 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002049 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002050 int err;
2051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002052 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002053
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002054 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002056 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002057 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2058 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002059 goto failed;
2060 }
2061
Andre Guedes92c4c202012-06-07 19:05:44 -03002062 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063 if (!uuid) {
2064 err = -ENOMEM;
2065 goto failed;
2066 }
2067
2068 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002069 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002070 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002071
Johan Hedbergde66aa62013-01-27 00:31:27 +02002072 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002073
Johan Hedberg890ea892013-03-15 17:06:52 -05002074 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002075
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002076 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002077 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002078
Johan Hedberg92da6092013-03-15 17:06:55 -05002079 err = hci_req_run(&req, add_uuid_complete);
2080 if (err < 0) {
2081 if (err != -ENODATA)
2082 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002083
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002084 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2085 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002086 goto failed;
2087 }
2088
2089 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002090 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002091 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002092 goto failed;
2093 }
2094
2095 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002096
2097failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002098 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099 return err;
2100}
2101
Johan Hedberg24b78d02012-02-23 23:24:30 +02002102static bool enable_service_cache(struct hci_dev *hdev)
2103{
2104 if (!hdev_is_powered(hdev))
2105 return false;
2106
Marcel Holtmann238be782015-03-13 02:11:06 -07002107 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002108 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2109 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002110 return true;
2111 }
2112
2113 return false;
2114}
2115
Marcel Holtmann1904a852015-01-11 13:50:44 -08002116static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002117{
2118 BT_DBG("status 0x%02x", status);
2119
2120 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2121}
2122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002123static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002124 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002126 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002127 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002128 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129 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 -05002130 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002131 int err, found;
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002136
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002137 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002138 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2139 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002140 goto unlock;
2141 }
2142
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002143 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002144 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002145
Johan Hedberg24b78d02012-02-23 23:24:30 +02002146 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002147 err = mgmt_cmd_complete(sk, hdev->id,
2148 MGMT_OP_REMOVE_UUID,
2149 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002150 goto unlock;
2151 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002152
Johan Hedberg9246a862012-02-23 21:33:16 +02002153 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002154 }
2155
2156 found = 0;
2157
Johan Hedberg056341c2013-01-27 00:31:30 +02002158 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002159 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2160 continue;
2161
2162 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002163 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164 found++;
2165 }
2166
2167 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002168 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2169 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002170 goto unlock;
2171 }
2172
Johan Hedberg9246a862012-02-23 21:33:16 +02002173update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002174 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002175
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002176 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002177 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002178
Johan Hedberg92da6092013-03-15 17:06:55 -05002179 err = hci_req_run(&req, remove_uuid_complete);
2180 if (err < 0) {
2181 if (err != -ENODATA)
2182 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002183
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002184 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2185 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002186 goto unlock;
2187 }
2188
2189 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002190 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002191 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002192 goto unlock;
2193 }
2194
2195 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002196
2197unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002198 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002199 return err;
2200}
2201
Marcel Holtmann1904a852015-01-11 13:50:44 -08002202static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002203{
2204 BT_DBG("status 0x%02x", status);
2205
2206 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2207}
2208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002213 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002214 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002215 int err;
2216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002217 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002218
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002219 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002220 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2221 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002222
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002223 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002224
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002225 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002226 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2227 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002228 goto unlock;
2229 }
2230
2231 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002234 goto unlock;
2235 }
2236
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002237 hdev->major_class = cp->major;
2238 hdev->minor_class = cp->minor;
2239
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002240 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002241 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2242 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002243 goto unlock;
2244 }
2245
Johan Hedberg890ea892013-03-15 17:06:52 -05002246 hci_req_init(&req, hdev);
2247
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002248 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002249 hci_dev_unlock(hdev);
2250 cancel_delayed_work_sync(&hdev->service_cache);
2251 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002252 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002253 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002254
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002255 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002256
Johan Hedberg92da6092013-03-15 17:06:55 -05002257 err = hci_req_run(&req, set_class_complete);
2258 if (err < 0) {
2259 if (err != -ENODATA)
2260 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002261
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002262 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2263 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002264 goto unlock;
2265 }
2266
2267 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002268 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002269 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002270 goto unlock;
2271 }
2272
2273 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002274
Johan Hedbergb5235a62012-02-21 14:32:24 +02002275unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002276 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002277 return err;
2278}
2279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002281 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002282{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002284 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2285 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002286 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002287 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002288 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002289
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002290 BT_DBG("request for %s", hdev->name);
2291
2292 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2294 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002295
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002296 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002297 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002298 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2299 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002300 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2301 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002302 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002303
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05002304 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002305 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002306 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2307 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002308 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2309 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002310 }
2311
Johan Hedberg4ae14302013-01-20 14:27:13 +02002312 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002313 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2314 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002315
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002316 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002317 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002318
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002319 for (i = 0; i < key_count; i++) {
2320 struct mgmt_link_key_info *key = &cp->keys[i];
2321
Marcel Holtmann8e991132014-01-10 02:07:25 -08002322 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002323 return mgmt_cmd_status(sk, hdev->id,
2324 MGMT_OP_LOAD_LINK_KEYS,
2325 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002326 }
2327
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002328 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002329
2330 hci_link_keys_clear(hdev);
2331
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002332 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002333 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002334 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002335 changed = hci_dev_test_and_clear_flag(hdev,
2336 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002337
2338 if (changed)
2339 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002340
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002341 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002342 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002343
Johan Hedberg58e92932014-06-24 14:00:26 +03002344 /* Always ignore debug keys and require a new pairing if
2345 * the user wants to use them.
2346 */
2347 if (key->type == HCI_LK_DEBUG_COMBINATION)
2348 continue;
2349
Johan Hedberg7652ff62014-06-24 13:15:49 +03002350 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2351 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002352 }
2353
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002354 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002355
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002356 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002357
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002358 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002359}
2360
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002361static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002363{
2364 struct mgmt_ev_device_unpaired ev;
2365
2366 bacpy(&ev.addr.bdaddr, bdaddr);
2367 ev.addr.type = addr_type;
2368
2369 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002370 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002371}
2372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002373static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002374 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002375{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002376 struct mgmt_cp_unpair_device *cp = data;
2377 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002378 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002379 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002380 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002381 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002382 int err;
2383
Johan Hedberga8a1d192011-11-10 15:54:38 +02002384 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002385 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2386 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002387
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002388 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002389 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2390 MGMT_STATUS_INVALID_PARAMS,
2391 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002392
Johan Hedberg118da702013-01-20 14:27:20 +02002393 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002394 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2395 MGMT_STATUS_INVALID_PARAMS,
2396 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002397
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002398 hci_dev_lock(hdev);
2399
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002400 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002401 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2402 MGMT_STATUS_NOT_POWERED, &rp,
2403 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002404 goto unlock;
2405 }
2406
Johan Hedberge0b2b272014-02-18 17:14:31 +02002407 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002408 /* If disconnection is requested, then look up the
2409 * connection. If the remote device is connected, it
2410 * will be later used to terminate the link.
2411 *
2412 * Setting it to NULL explicitly will cause no
2413 * termination of the link.
2414 */
2415 if (cp->disconnect)
2416 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2417 &cp->addr.bdaddr);
2418 else
2419 conn = NULL;
2420
Johan Hedberg124f6e32012-02-09 13:50:12 +02002421 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002422 if (err < 0) {
2423 err = mgmt_cmd_complete(sk, hdev->id,
2424 MGMT_OP_UNPAIR_DEVICE,
2425 MGMT_STATUS_NOT_PAIRED, &rp,
2426 sizeof(rp));
2427 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002428 }
2429
Johan Hedbergec182f02015-10-21 18:03:03 +03002430 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002431 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002432
Johan Hedbergec182f02015-10-21 18:03:03 +03002433 /* LE address type */
2434 addr_type = le_addr_type(cp->addr.type);
2435
Matias Karhumaacb28c302018-09-26 09:13:46 +03002436 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2437 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002438 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002439 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2440 MGMT_STATUS_NOT_PAIRED, &rp,
2441 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002442 goto unlock;
2443 }
2444
Johan Hedbergec182f02015-10-21 18:03:03 +03002445 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2446 if (!conn) {
2447 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2448 goto done;
2449 }
2450
Johan Hedbergc81d5552015-10-22 09:38:35 +03002451
Johan Hedbergec182f02015-10-21 18:03:03 +03002452 /* Defer clearing up the connection parameters until closing to
2453 * give a chance of keeping them if a repairing happens.
2454 */
2455 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2456
Johan Hedbergfc643612015-10-22 09:38:31 +03002457 /* Disable auto-connection parameters if present */
2458 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2459 if (params) {
2460 if (params->explicit_connect)
2461 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2462 else
2463 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2464 }
2465
Johan Hedbergec182f02015-10-21 18:03:03 +03002466 /* If disconnection is not requested, then clear the connection
2467 * variable so that the link is not terminated.
2468 */
2469 if (!cp->disconnect)
2470 conn = NULL;
2471
2472done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002473 /* If the connection variable is set, then termination of the
2474 * link is requested.
2475 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002476 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002477 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2478 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002479 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002480 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002481 }
2482
Johan Hedberg124f6e32012-02-09 13:50:12 +02002483 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002484 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002485 if (!cmd) {
2486 err = -ENOMEM;
2487 goto unlock;
2488 }
2489
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002490 cmd->cmd_complete = addr_cmd_complete;
2491
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002492 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002493 if (err < 0)
2494 mgmt_pending_remove(cmd);
2495
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002496unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002497 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002498 return err;
2499}
2500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002501static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002502 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002503{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002505 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002506 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002507 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002508 int err;
2509
2510 BT_DBG("");
2511
Johan Hedberg06a63b12013-01-20 14:27:21 +02002512 memset(&rp, 0, sizeof(rp));
2513 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2514 rp.addr.type = cp->addr.type;
2515
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002516 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002517 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2518 MGMT_STATUS_INVALID_PARAMS,
2519 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002520
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002522
2523 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002524 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2525 MGMT_STATUS_NOT_POWERED, &rp,
2526 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002527 goto failed;
2528 }
2529
Johan Hedberg333ae952015-03-17 13:48:47 +02002530 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002531 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2532 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002533 goto failed;
2534 }
2535
Andre Guedes591f47f2012-04-24 21:02:49 -03002536 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002537 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2538 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002539 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002540 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2541 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002542
Vishal Agarwalf9607272012-06-13 05:32:43 +05302543 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002544 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2545 MGMT_STATUS_NOT_CONNECTED, &rp,
2546 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002547 goto failed;
2548 }
2549
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002550 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002551 if (!cmd) {
2552 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002553 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002554 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002555
Johan Hedbergf5818c22014-12-05 13:36:02 +02002556 cmd->cmd_complete = generic_cmd_complete;
2557
Johan Hedberge3f2f922014-08-18 20:33:33 +03002558 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002559 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002560 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002561
2562failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002563 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002564 return err;
2565}
2566
Andre Guedes57c14772012-04-24 21:02:50 -03002567static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002568{
2569 switch (link_type) {
2570 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002571 switch (addr_type) {
2572 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002573 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002574
Johan Hedberg48264f02011-11-09 13:58:58 +02002575 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002576 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002577 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002578 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002579
Johan Hedberg4c659c32011-11-07 23:13:39 +02002580 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002581 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002582 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002583 }
2584}
2585
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002586static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2587 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002588{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002589 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002590 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002591 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002592 int err;
2593 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002594
2595 BT_DBG("");
2596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002597 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002598
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002599 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002600 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2601 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002602 goto unlock;
2603 }
2604
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002605 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002606 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2607 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002608 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002609 }
2610
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002611 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002612 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002613 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002614 err = -ENOMEM;
2615 goto unlock;
2616 }
2617
Johan Hedberg2784eb42011-01-21 13:56:35 +02002618 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002619 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002620 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2621 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002622 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002623 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002624 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002625 continue;
2626 i++;
2627 }
2628
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002629 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002630
Johan Hedberg4c659c32011-11-07 23:13:39 +02002631 /* Recalculate length in case of filtered SCO connections, etc */
2632 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002633
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002634 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2635 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002636
Johan Hedberga38528f2011-01-22 06:46:43 +02002637 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002638
2639unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002640 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002641 return err;
2642}
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002646{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002647 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002648 int err;
2649
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002650 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002651 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002652 if (!cmd)
2653 return -ENOMEM;
2654
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002655 cmd->cmd_complete = addr_cmd_complete;
2656
Johan Hedbergd8457692012-02-17 14:24:57 +02002657 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002658 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002659 if (err < 0)
2660 mgmt_pending_remove(cmd);
2661
2662 return err;
2663}
2664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002665static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002666 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002667{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002668 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002669 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002670 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002671 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002672 int err;
2673
2674 BT_DBG("");
2675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002676 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002677
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002678 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002679 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2680 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002681 goto failed;
2682 }
2683
Johan Hedbergd8457692012-02-17 14:24:57 +02002684 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002685 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002686 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2687 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002688 goto failed;
2689 }
2690
2691 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002692 struct mgmt_cp_pin_code_neg_reply ncp;
2693
2694 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002695
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002696 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002699 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002700 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2701 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002702
2703 goto failed;
2704 }
2705
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002706 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002707 if (!cmd) {
2708 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002709 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002710 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002712 cmd->cmd_complete = addr_cmd_complete;
2713
Johan Hedbergd8457692012-02-17 14:24:57 +02002714 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002716 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717
2718 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2719 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002720 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002721
2722failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002723 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002724 return err;
2725}
2726
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002727static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2728 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002729{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002730 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002731
2732 BT_DBG("");
2733
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002734 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002735 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2736 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002737
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002738 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002739
2740 hdev->io_capability = cp->io_capability;
2741
2742 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002743 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002744
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002745 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002746
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002747 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2748 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002749}
2750
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002751static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002752{
2753 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002754 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002755
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002756 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002757 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2758 continue;
2759
Johan Hedberge9a416b2011-02-19 12:05:56 -03002760 if (cmd->user_data != conn)
2761 continue;
2762
2763 return cmd;
2764 }
2765
2766 return NULL;
2767}
2768
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002769static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002770{
2771 struct mgmt_rp_pair_device rp;
2772 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002773 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002774
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002775 bacpy(&rp.addr.bdaddr, &conn->dst);
2776 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002777
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002778 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2779 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002780
2781 /* So we don't get further callbacks for this connection */
2782 conn->connect_cfm_cb = NULL;
2783 conn->security_cfm_cb = NULL;
2784 conn->disconn_cfm_cb = NULL;
2785
David Herrmann76a68ba2013-04-06 20:28:37 +02002786 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002787
2788 /* The device is paired so there is no need to remove
2789 * its connection parameters anymore.
2790 */
2791 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002792
2793 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002794
2795 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002796}
2797
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002798void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2799{
2800 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002801 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002802
2803 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002804 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002805 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002806 mgmt_pending_remove(cmd);
2807 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002808}
2809
Johan Hedberge9a416b2011-02-19 12:05:56 -03002810static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2811{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002812 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002813
2814 BT_DBG("status %u", status);
2815
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002816 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002817 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002818 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002819 return;
2820 }
2821
2822 cmd->cmd_complete(cmd, mgmt_status(status));
2823 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002824}
2825
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002826static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302827{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002828 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302829
2830 BT_DBG("status %u", status);
2831
2832 if (!status)
2833 return;
2834
2835 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002836 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302837 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002838 return;
2839 }
2840
2841 cmd->cmd_complete(cmd, mgmt_status(status));
2842 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302843}
2844
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002845static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002846 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002847{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002848 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002849 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002850 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002851 u8 sec_level, auth_type;
2852 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002853 int err;
2854
2855 BT_DBG("");
2856
Szymon Jancf950a30e2013-01-18 12:48:07 +01002857 memset(&rp, 0, sizeof(rp));
2858 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2859 rp.addr.type = cp->addr.type;
2860
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002861 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002862 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2863 MGMT_STATUS_INVALID_PARAMS,
2864 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002865
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002866 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002867 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2868 MGMT_STATUS_INVALID_PARAMS,
2869 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002871 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002872
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002873 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002874 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2875 MGMT_STATUS_NOT_POWERED, &rp,
2876 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002877 goto unlock;
2878 }
2879
Johan Hedberg55e76b32015-03-10 22:34:40 +02002880 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2881 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2882 MGMT_STATUS_ALREADY_PAIRED, &rp,
2883 sizeof(rp));
2884 goto unlock;
2885 }
2886
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002887 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002888 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002889
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002890 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002891 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2892 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002893 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002894 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002895 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002896
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002897 /* When pairing a new device, it is expected to remember
2898 * this device for future connections. Adding the connection
2899 * parameter information ahead of time allows tracking
2900 * of the slave preferred values and will speed up any
2901 * further connection establishment.
2902 *
2903 * If connection parameters already exist, then they
2904 * will be kept and this function does nothing.
2905 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002906 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2907
2908 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2909 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002910
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002911 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2912 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002913 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002914 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002915
Ville Tervo30e76272011-02-22 16:10:53 -03002916 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002917 int status;
2918
2919 if (PTR_ERR(conn) == -EBUSY)
2920 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002921 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2922 status = MGMT_STATUS_NOT_SUPPORTED;
2923 else if (PTR_ERR(conn) == -ECONNREFUSED)
2924 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002925 else
2926 status = MGMT_STATUS_CONNECT_FAILED;
2927
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002928 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2929 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002930 goto unlock;
2931 }
2932
2933 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002934 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002935 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2936 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002937 goto unlock;
2938 }
2939
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002940 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002941 if (!cmd) {
2942 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002943 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002944 goto unlock;
2945 }
2946
Johan Hedberg04ab2742014-12-05 13:36:04 +02002947 cmd->cmd_complete = pairing_complete;
2948
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002949 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002950 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002951 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002952 conn->security_cfm_cb = pairing_complete_cb;
2953 conn->disconn_cfm_cb = pairing_complete_cb;
2954 } else {
2955 conn->connect_cfm_cb = le_pairing_complete_cb;
2956 conn->security_cfm_cb = le_pairing_complete_cb;
2957 conn->disconn_cfm_cb = le_pairing_complete_cb;
2958 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002959
Johan Hedberge9a416b2011-02-19 12:05:56 -03002960 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002961 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002962
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002963 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002964 hci_conn_security(conn, sec_level, auth_type, true)) {
2965 cmd->cmd_complete(cmd, 0);
2966 mgmt_pending_remove(cmd);
2967 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002968
2969 err = 0;
2970
2971unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002972 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002973 return err;
2974}
2975
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002976static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2977 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002978{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002979 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002980 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002981 struct hci_conn *conn;
2982 int err;
2983
2984 BT_DBG("");
2985
Johan Hedberg28424702012-02-02 04:02:29 +02002986 hci_dev_lock(hdev);
2987
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002988 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002989 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2990 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002991 goto unlock;
2992 }
2993
Johan Hedberg333ae952015-03-17 13:48:47 +02002994 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002995 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002996 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2997 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002998 goto unlock;
2999 }
3000
3001 conn = cmd->user_data;
3002
3003 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003004 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3005 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003006 goto unlock;
3007 }
3008
Johan Hedberga511b352014-12-11 21:45:45 +02003009 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3010 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003011
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003012 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3013 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003014unlock:
3015 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003016 return err;
3017}
3018
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003019static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003020 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003021 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003022{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003023 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003024 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003025 int err;
3026
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003027 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003028
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003029 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003030 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3031 MGMT_STATUS_NOT_POWERED, addr,
3032 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003033 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003034 }
3035
Johan Hedberg1707c602013-03-15 17:07:15 -05003036 if (addr->type == BDADDR_BREDR)
3037 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003038 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003039 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3040 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003041
Johan Hedberg272d90d2012-02-09 15:26:12 +02003042 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003043 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3044 MGMT_STATUS_NOT_CONNECTED, addr,
3045 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003046 goto done;
3047 }
3048
Johan Hedberg1707c602013-03-15 17:07:15 -05003049 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003050 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003051 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003052 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3053 MGMT_STATUS_SUCCESS, addr,
3054 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003055 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003056 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3057 MGMT_STATUS_FAILED, addr,
3058 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003059
Brian Gix47c15e22011-11-16 13:53:14 -08003060 goto done;
3061 }
3062
Johan Hedberg1707c602013-03-15 17:07:15 -05003063 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003064 if (!cmd) {
3065 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003066 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003067 }
3068
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003069 cmd->cmd_complete = addr_cmd_complete;
3070
Brian Gix0df4c182011-11-16 13:53:13 -08003071 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003072 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3073 struct hci_cp_user_passkey_reply cp;
3074
Johan Hedberg1707c602013-03-15 17:07:15 -05003075 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003076 cp.passkey = passkey;
3077 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3078 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003079 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3080 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003081
Johan Hedberga664b5b2011-02-19 12:06:02 -03003082 if (err < 0)
3083 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003084
Brian Gix0df4c182011-11-16 13:53:13 -08003085done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003086 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003087 return err;
3088}
3089
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303090static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3091 void *data, u16 len)
3092{
3093 struct mgmt_cp_pin_code_neg_reply *cp = data;
3094
3095 BT_DBG("");
3096
Johan Hedberg1707c602013-03-15 17:07:15 -05003097 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303098 MGMT_OP_PIN_CODE_NEG_REPLY,
3099 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3100}
3101
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003102static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3103 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003104{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003105 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003106
3107 BT_DBG("");
3108
3109 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003110 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3111 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003112
Johan Hedberg1707c602013-03-15 17:07:15 -05003113 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003114 MGMT_OP_USER_CONFIRM_REPLY,
3115 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003116}
3117
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003118static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003119 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003120{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003121 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003122
3123 BT_DBG("");
3124
Johan Hedberg1707c602013-03-15 17:07:15 -05003125 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3127 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003128}
3129
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003130static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3131 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003132{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003133 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003134
3135 BT_DBG("");
3136
Johan Hedberg1707c602013-03-15 17:07:15 -05003137 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003138 MGMT_OP_USER_PASSKEY_REPLY,
3139 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003140}
3141
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003142static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003143 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003144{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003145 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003146
3147 BT_DBG("");
3148
Johan Hedberg1707c602013-03-15 17:07:15 -05003149 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003150 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3151 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003152}
3153
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003154static void adv_expire(struct hci_dev *hdev, u32 flags)
3155{
3156 struct adv_info *adv_instance;
3157 struct hci_request req;
3158 int err;
3159
3160 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3161 if (!adv_instance)
3162 return;
3163
3164 /* stop if current instance doesn't need to be changed */
3165 if (!(adv_instance->flags & flags))
3166 return;
3167
3168 cancel_adv_timeout(hdev);
3169
3170 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3171 if (!adv_instance)
3172 return;
3173
3174 hci_req_init(&req, hdev);
3175 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3176 true);
3177 if (err)
3178 return;
3179
3180 hci_req_run(&req, NULL);
3181}
3182
Marcel Holtmann1904a852015-01-11 13:50:44 -08003183static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003184{
3185 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003186 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003187
3188 BT_DBG("status 0x%02x", status);
3189
3190 hci_dev_lock(hdev);
3191
Johan Hedberg333ae952015-03-17 13:48:47 +02003192 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003193 if (!cmd)
3194 goto unlock;
3195
3196 cp = cmd->param;
3197
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003198 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003199 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3200 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003201 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003202 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3203 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003204
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003205 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3206 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3207 }
3208
Johan Hedberg13928972013-03-15 17:07:00 -05003209 mgmt_pending_remove(cmd);
3210
3211unlock:
3212 hci_dev_unlock(hdev);
3213}
3214
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003215static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003217{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003218 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003219 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003220 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003221 int err;
3222
3223 BT_DBG("");
3224
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003225 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003226
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003227 /* If the old values are the same as the new ones just return a
3228 * direct command complete event.
3229 */
3230 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3231 !memcmp(hdev->short_name, cp->short_name,
3232 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003233 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3234 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003235 goto failed;
3236 }
3237
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003238 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003239
Johan Hedbergb5235a62012-02-21 14:32:24 +02003240 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003241 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003242
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003243 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3244 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003245 if (err < 0)
3246 goto failed;
3247
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003248 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3249 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003250 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003251
Johan Hedbergb5235a62012-02-21 14:32:24 +02003252 goto failed;
3253 }
3254
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003255 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003256 if (!cmd) {
3257 err = -ENOMEM;
3258 goto failed;
3259 }
3260
Johan Hedberg13928972013-03-15 17:07:00 -05003261 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3262
Johan Hedberg890ea892013-03-15 17:06:52 -05003263 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003264
3265 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003266 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003267 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003268 }
3269
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003270 /* The name is stored in the scan response data and so
3271 * no need to udpate the advertising data here.
3272 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003273 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003274 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003275
Johan Hedberg13928972013-03-15 17:07:00 -05003276 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003277 if (err < 0)
3278 mgmt_pending_remove(cmd);
3279
3280failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003281 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003282 return err;
3283}
3284
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003285static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3286 u16 len)
3287{
3288 struct mgmt_cp_set_appearance *cp = data;
3289 u16 apperance;
3290 int err;
3291
3292 BT_DBG("");
3293
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003294 if (!lmp_le_capable(hdev))
3295 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3296 MGMT_STATUS_NOT_SUPPORTED);
3297
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003298 apperance = le16_to_cpu(cp->appearance);
3299
3300 hci_dev_lock(hdev);
3301
3302 if (hdev->appearance != apperance) {
3303 hdev->appearance = apperance;
3304
3305 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3306 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003307
3308 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003309 }
3310
3311 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3312 0);
3313
3314 hci_dev_unlock(hdev);
3315
3316 return err;
3317}
3318
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303319static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3320 void *data, u16 len)
3321{
3322 struct mgmt_rp_get_phy_confguration rp;
3323
3324 BT_DBG("sock %p %s", sk, hdev->name);
3325
3326 hci_dev_lock(hdev);
3327
3328 memset(&rp, 0, sizeof(rp));
3329
3330 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3331 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3332 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3333
3334 hci_dev_unlock(hdev);
3335
3336 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3337 &rp, sizeof(rp));
3338}
3339
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303340int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3341{
3342 struct mgmt_ev_phy_configuration_changed ev;
3343
3344 memset(&ev, 0, sizeof(ev));
3345
3346 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3347
3348 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3349 sizeof(ev), skip);
3350}
3351
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303352static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3353 u16 opcode, struct sk_buff *skb)
3354{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303355 struct mgmt_pending_cmd *cmd;
3356
3357 BT_DBG("status 0x%02x", status);
3358
3359 hci_dev_lock(hdev);
3360
3361 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3362 if (!cmd)
3363 goto unlock;
3364
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303365 if (status) {
3366 mgmt_cmd_status(cmd->sk, hdev->id,
3367 MGMT_OP_SET_PHY_CONFIGURATION,
3368 mgmt_status(status));
3369 } else {
3370 mgmt_cmd_complete(cmd->sk, hdev->id,
3371 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3372 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303373
3374 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303375 }
3376
3377 mgmt_pending_remove(cmd);
3378
3379unlock:
3380 hci_dev_unlock(hdev);
3381}
3382
3383static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3384 void *data, u16 len)
3385{
3386 struct mgmt_cp_set_phy_confguration *cp = data;
3387 struct hci_cp_le_set_default_phy cp_phy;
3388 struct mgmt_pending_cmd *cmd;
3389 struct hci_request req;
3390 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3391 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303392 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303393 int err;
3394
3395 BT_DBG("sock %p %s", sk, hdev->name);
3396
3397 configurable_phys = get_configurable_phys(hdev);
3398 supported_phys = get_supported_phys(hdev);
3399 selected_phys = __le32_to_cpu(cp->selected_phys);
3400
3401 if (selected_phys & ~supported_phys)
3402 return mgmt_cmd_status(sk, hdev->id,
3403 MGMT_OP_SET_PHY_CONFIGURATION,
3404 MGMT_STATUS_INVALID_PARAMS);
3405
3406 unconfigure_phys = supported_phys & ~configurable_phys;
3407
3408 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3409 return mgmt_cmd_status(sk, hdev->id,
3410 MGMT_OP_SET_PHY_CONFIGURATION,
3411 MGMT_STATUS_INVALID_PARAMS);
3412
3413 if (selected_phys == get_selected_phys(hdev))
3414 return mgmt_cmd_complete(sk, hdev->id,
3415 MGMT_OP_SET_PHY_CONFIGURATION,
3416 0, NULL, 0);
3417
3418 hci_dev_lock(hdev);
3419
3420 if (!hdev_is_powered(hdev)) {
3421 err = mgmt_cmd_status(sk, hdev->id,
3422 MGMT_OP_SET_PHY_CONFIGURATION,
3423 MGMT_STATUS_REJECTED);
3424 goto unlock;
3425 }
3426
3427 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3428 err = mgmt_cmd_status(sk, hdev->id,
3429 MGMT_OP_SET_PHY_CONFIGURATION,
3430 MGMT_STATUS_BUSY);
3431 goto unlock;
3432 }
3433
3434 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3435 pkt_type |= (HCI_DH3 | HCI_DM3);
3436 else
3437 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3438
3439 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3440 pkt_type |= (HCI_DH5 | HCI_DM5);
3441 else
3442 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3443
3444 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3445 pkt_type &= ~HCI_2DH1;
3446 else
3447 pkt_type |= HCI_2DH1;
3448
3449 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3450 pkt_type &= ~HCI_2DH3;
3451 else
3452 pkt_type |= HCI_2DH3;
3453
3454 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3455 pkt_type &= ~HCI_2DH5;
3456 else
3457 pkt_type |= HCI_2DH5;
3458
3459 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3460 pkt_type &= ~HCI_3DH1;
3461 else
3462 pkt_type |= HCI_3DH1;
3463
3464 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3465 pkt_type &= ~HCI_3DH3;
3466 else
3467 pkt_type |= HCI_3DH3;
3468
3469 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3470 pkt_type &= ~HCI_3DH5;
3471 else
3472 pkt_type |= HCI_3DH5;
3473
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303474 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303475 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303476 changed = true;
3477 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303478
3479 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3480 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303481 if (changed)
3482 mgmt_phy_configuration_changed(hdev, sk);
3483
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303484 err = mgmt_cmd_complete(sk, hdev->id,
3485 MGMT_OP_SET_PHY_CONFIGURATION,
3486 0, NULL, 0);
3487
3488 goto unlock;
3489 }
3490
3491 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3492 len);
3493 if (!cmd) {
3494 err = -ENOMEM;
3495 goto unlock;
3496 }
3497
3498 hci_req_init(&req, hdev);
3499
3500 memset(&cp_phy, 0, sizeof(cp_phy));
3501
3502 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3503 cp_phy.all_phys |= 0x01;
3504
3505 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3506 cp_phy.all_phys |= 0x02;
3507
3508 if (selected_phys & MGMT_PHY_LE_1M_TX)
3509 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3510
3511 if (selected_phys & MGMT_PHY_LE_2M_TX)
3512 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3513
3514 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3515 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3516
3517 if (selected_phys & MGMT_PHY_LE_1M_RX)
3518 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3519
3520 if (selected_phys & MGMT_PHY_LE_2M_RX)
3521 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3522
3523 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3524 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3525
3526 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3527
3528 err = hci_req_run_skb(&req, set_default_phy_complete);
3529 if (err < 0)
3530 mgmt_pending_remove(cmd);
3531
3532unlock:
3533 hci_dev_unlock(hdev);
3534
3535 return err;
3536}
3537
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003538static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3539 u16 opcode, struct sk_buff *skb)
3540{
3541 struct mgmt_rp_read_local_oob_data mgmt_rp;
3542 size_t rp_size = sizeof(mgmt_rp);
3543 struct mgmt_pending_cmd *cmd;
3544
3545 BT_DBG("%s status %u", hdev->name, status);
3546
3547 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3548 if (!cmd)
3549 return;
3550
3551 if (status || !skb) {
3552 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3553 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3554 goto remove;
3555 }
3556
3557 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3558
3559 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3560 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3561
3562 if (skb->len < sizeof(*rp)) {
3563 mgmt_cmd_status(cmd->sk, hdev->id,
3564 MGMT_OP_READ_LOCAL_OOB_DATA,
3565 MGMT_STATUS_FAILED);
3566 goto remove;
3567 }
3568
3569 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3570 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3571
3572 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3573 } else {
3574 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3575
3576 if (skb->len < sizeof(*rp)) {
3577 mgmt_cmd_status(cmd->sk, hdev->id,
3578 MGMT_OP_READ_LOCAL_OOB_DATA,
3579 MGMT_STATUS_FAILED);
3580 goto remove;
3581 }
3582
3583 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3584 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3585
3586 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3587 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3588 }
3589
3590 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3591 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3592
3593remove:
3594 mgmt_pending_remove(cmd);
3595}
3596
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003597static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003598 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003599{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003600 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003601 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003602 int err;
3603
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003604 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003605
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003606 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003607
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003608 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003609 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3610 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003611 goto unlock;
3612 }
3613
Andre Guedes9a1a1992012-07-24 15:03:48 -03003614 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003615 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3616 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003617 goto unlock;
3618 }
3619
Johan Hedberg333ae952015-03-17 13:48:47 +02003620 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003621 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3622 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003623 goto unlock;
3624 }
3625
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003626 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003627 if (!cmd) {
3628 err = -ENOMEM;
3629 goto unlock;
3630 }
3631
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003632 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003633
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003634 if (bredr_sc_enabled(hdev))
3635 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3636 else
3637 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3638
3639 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003640 if (err < 0)
3641 mgmt_pending_remove(cmd);
3642
3643unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003644 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003645 return err;
3646}
3647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003648static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003649 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003650{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003651 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003652 int err;
3653
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003654 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003655
Johan Hedberg5d57e792015-01-23 10:10:38 +02003656 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003657 return mgmt_cmd_complete(sk, hdev->id,
3658 MGMT_OP_ADD_REMOTE_OOB_DATA,
3659 MGMT_STATUS_INVALID_PARAMS,
3660 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003661
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003662 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003663
Marcel Holtmannec109112014-01-10 02:07:30 -08003664 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3665 struct mgmt_cp_add_remote_oob_data *cp = data;
3666 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003667
Johan Hedbergc19a4952014-11-17 20:52:19 +02003668 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003669 err = mgmt_cmd_complete(sk, hdev->id,
3670 MGMT_OP_ADD_REMOTE_OOB_DATA,
3671 MGMT_STATUS_INVALID_PARAMS,
3672 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003673 goto unlock;
3674 }
3675
Marcel Holtmannec109112014-01-10 02:07:30 -08003676 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003677 cp->addr.type, cp->hash,
3678 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003679 if (err < 0)
3680 status = MGMT_STATUS_FAILED;
3681 else
3682 status = MGMT_STATUS_SUCCESS;
3683
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003684 err = mgmt_cmd_complete(sk, hdev->id,
3685 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3686 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003687 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3688 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003689 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003690 u8 status;
3691
Johan Hedberg86df9202014-10-26 20:52:27 +01003692 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003693 /* Enforce zero-valued 192-bit parameters as
3694 * long as legacy SMP OOB isn't implemented.
3695 */
3696 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3697 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003698 err = mgmt_cmd_complete(sk, hdev->id,
3699 MGMT_OP_ADD_REMOTE_OOB_DATA,
3700 MGMT_STATUS_INVALID_PARAMS,
3701 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003702 goto unlock;
3703 }
3704
Johan Hedberg86df9202014-10-26 20:52:27 +01003705 rand192 = NULL;
3706 hash192 = NULL;
3707 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003708 /* In case one of the P-192 values is set to zero,
3709 * then just disable OOB data for P-192.
3710 */
3711 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3712 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3713 rand192 = NULL;
3714 hash192 = NULL;
3715 } else {
3716 rand192 = cp->rand192;
3717 hash192 = cp->hash192;
3718 }
3719 }
3720
3721 /* In case one of the P-256 values is set to zero, then just
3722 * disable OOB data for P-256.
3723 */
3724 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3725 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3726 rand256 = NULL;
3727 hash256 = NULL;
3728 } else {
3729 rand256 = cp->rand256;
3730 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003731 }
3732
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003733 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003734 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003735 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003736 if (err < 0)
3737 status = MGMT_STATUS_FAILED;
3738 else
3739 status = MGMT_STATUS_SUCCESS;
3740
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003741 err = mgmt_cmd_complete(sk, hdev->id,
3742 MGMT_OP_ADD_REMOTE_OOB_DATA,
3743 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003744 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003745 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
3746 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003747 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3748 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003749 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003750
Johan Hedbergc19a4952014-11-17 20:52:19 +02003751unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003752 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003753 return err;
3754}
3755
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003756static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003757 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003758{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003759 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003760 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003761 int err;
3762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003763 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003764
Johan Hedbergc19a4952014-11-17 20:52:19 +02003765 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003766 return mgmt_cmd_complete(sk, hdev->id,
3767 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3768 MGMT_STATUS_INVALID_PARAMS,
3769 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003770
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003771 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003772
Johan Hedbergeedbd582014-11-15 09:34:23 +02003773 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3774 hci_remote_oob_data_clear(hdev);
3775 status = MGMT_STATUS_SUCCESS;
3776 goto done;
3777 }
3778
Johan Hedberg6928a922014-10-26 20:46:09 +01003779 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003780 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003781 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003782 else
Szymon Janca6785be2012-12-13 15:11:21 +01003783 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003784
Johan Hedbergeedbd582014-11-15 09:34:23 +02003785done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003786 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3787 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003789 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003790 return err;
3791}
3792
Johan Hedberge68f0722015-11-11 08:30:30 +02003793void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003794{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003795 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003796
Andre Guedes7c307722013-04-30 15:29:28 -03003797 BT_DBG("status %d", status);
3798
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003799 hci_dev_lock(hdev);
3800
Johan Hedberg333ae952015-03-17 13:48:47 +02003801 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003802 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003803 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003804
Johan Hedberg78b781c2016-01-05 13:19:32 +02003805 if (!cmd)
3806 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3807
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003808 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003809 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003810 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003811 }
3812
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003813 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003814}
3815
Johan Hedberg591752a2015-11-11 08:11:24 +02003816static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3817 uint8_t *mgmt_status)
3818{
3819 switch (type) {
3820 case DISCOV_TYPE_LE:
3821 *mgmt_status = mgmt_le_support(hdev);
3822 if (*mgmt_status)
3823 return false;
3824 break;
3825 case DISCOV_TYPE_INTERLEAVED:
3826 *mgmt_status = mgmt_le_support(hdev);
3827 if (*mgmt_status)
3828 return false;
3829 /* Intentional fall-through */
3830 case DISCOV_TYPE_BREDR:
3831 *mgmt_status = mgmt_bredr_support(hdev);
3832 if (*mgmt_status)
3833 return false;
3834 break;
3835 default:
3836 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3837 return false;
3838 }
3839
3840 return true;
3841}
3842
Johan Hedberg78b781c2016-01-05 13:19:32 +02003843static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3844 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003845{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003846 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003847 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003848 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003849 int err;
3850
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003851 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003852
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003853 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003854
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003855 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003856 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003857 MGMT_STATUS_NOT_POWERED,
3858 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003859 goto failed;
3860 }
3861
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003862 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003863 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003864 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3865 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003866 goto failed;
3867 }
3868
Johan Hedberg591752a2015-11-11 08:11:24 +02003869 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003870 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3871 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003872 goto failed;
3873 }
3874
Marcel Holtmann22078802014-12-05 11:45:22 +01003875 /* Clear the discovery filter first to free any previously
3876 * allocated memory for the UUID list.
3877 */
3878 hci_discovery_filter_clear(hdev);
3879
Andre Guedes4aab14e2012-02-17 20:39:36 -03003880 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003881 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003882 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3883 hdev->discovery.limited = true;
3884 else
3885 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003886
Johan Hedberg78b781c2016-01-05 13:19:32 +02003887 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003888 if (!cmd) {
3889 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003890 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003891 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003892
Johan Hedberge68f0722015-11-11 08:30:30 +02003893 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003894
3895 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003896 queue_work(hdev->req_workqueue, &hdev->discov_update);
3897 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003898
3899failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003900 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003901 return err;
3902}
3903
Johan Hedberg78b781c2016-01-05 13:19:32 +02003904static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3905 void *data, u16 len)
3906{
3907 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3908 data, len);
3909}
3910
3911static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3912 void *data, u16 len)
3913{
3914 return start_discovery_internal(sk, hdev,
3915 MGMT_OP_START_LIMITED_DISCOVERY,
3916 data, len);
3917}
3918
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003919static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3920 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003921{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003922 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3923 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003924}
3925
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003926static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3927 void *data, u16 len)
3928{
3929 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003930 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003931 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3932 u16 uuid_count, expected_len;
3933 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003934 int err;
3935
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003936 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003937
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003938 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003939
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003940 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003941 err = mgmt_cmd_complete(sk, hdev->id,
3942 MGMT_OP_START_SERVICE_DISCOVERY,
3943 MGMT_STATUS_NOT_POWERED,
3944 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003945 goto failed;
3946 }
3947
3948 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003949 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003950 err = mgmt_cmd_complete(sk, hdev->id,
3951 MGMT_OP_START_SERVICE_DISCOVERY,
3952 MGMT_STATUS_BUSY, &cp->type,
3953 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003954 goto failed;
3955 }
3956
3957 uuid_count = __le16_to_cpu(cp->uuid_count);
3958 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003959 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
3960 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003961 err = mgmt_cmd_complete(sk, hdev->id,
3962 MGMT_OP_START_SERVICE_DISCOVERY,
3963 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3964 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003965 goto failed;
3966 }
3967
3968 expected_len = sizeof(*cp) + uuid_count * 16;
3969 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003970 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
3971 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003972 err = mgmt_cmd_complete(sk, hdev->id,
3973 MGMT_OP_START_SERVICE_DISCOVERY,
3974 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3975 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003976 goto failed;
3977 }
3978
Johan Hedberg591752a2015-11-11 08:11:24 +02003979 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3980 err = mgmt_cmd_complete(sk, hdev->id,
3981 MGMT_OP_START_SERVICE_DISCOVERY,
3982 status, &cp->type, sizeof(cp->type));
3983 goto failed;
3984 }
3985
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003986 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003987 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003988 if (!cmd) {
3989 err = -ENOMEM;
3990 goto failed;
3991 }
3992
Johan Hedberg2922a942014-12-05 13:36:06 +02003993 cmd->cmd_complete = service_discovery_cmd_complete;
3994
Marcel Holtmann22078802014-12-05 11:45:22 +01003995 /* Clear the discovery filter first to free any previously
3996 * allocated memory for the UUID list.
3997 */
3998 hci_discovery_filter_clear(hdev);
3999
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004000 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004001 hdev->discovery.type = cp->type;
4002 hdev->discovery.rssi = cp->rssi;
4003 hdev->discovery.uuid_count = uuid_count;
4004
4005 if (uuid_count > 0) {
4006 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4007 GFP_KERNEL);
4008 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004009 err = mgmt_cmd_complete(sk, hdev->id,
4010 MGMT_OP_START_SERVICE_DISCOVERY,
4011 MGMT_STATUS_FAILED,
4012 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004013 mgmt_pending_remove(cmd);
4014 goto failed;
4015 }
4016 }
4017
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004018 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004019 queue_work(hdev->req_workqueue, &hdev->discov_update);
4020 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004021
4022failed:
4023 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004024 return err;
4025}
4026
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004027void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004028{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004029 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004030
Andre Guedes0e05bba2013-04-30 15:29:33 -03004031 BT_DBG("status %d", status);
4032
4033 hci_dev_lock(hdev);
4034
Johan Hedberg333ae952015-03-17 13:48:47 +02004035 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004036 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004037 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004038 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004039 }
4040
Andre Guedes0e05bba2013-04-30 15:29:33 -03004041 hci_dev_unlock(hdev);
4042}
4043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004044static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004045 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004046{
Johan Hedbergd9306502012-02-20 23:25:18 +02004047 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004048 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004049 int err;
4050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004051 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004052
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004053 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004054
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004055 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004056 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4057 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4058 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004059 goto unlock;
4060 }
4061
4062 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004063 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4064 MGMT_STATUS_INVALID_PARAMS,
4065 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004066 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004067 }
4068
Johan Hedberg2922a942014-12-05 13:36:06 +02004069 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004070 if (!cmd) {
4071 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004072 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004073 }
4074
Johan Hedberg2922a942014-12-05 13:36:06 +02004075 cmd->cmd_complete = generic_cmd_complete;
4076
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004077 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4078 queue_work(hdev->req_workqueue, &hdev->discov_update);
4079 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004080
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004081unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004082 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004083 return err;
4084}
4085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004086static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004087 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004089 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004090 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004091 int err;
4092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004093 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004094
Johan Hedberg561aafb2012-01-04 13:31:59 +02004095 hci_dev_lock(hdev);
4096
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004097 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004098 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4099 MGMT_STATUS_FAILED, &cp->addr,
4100 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004101 goto failed;
4102 }
4103
Johan Hedberga198e7b2012-02-17 14:27:06 +02004104 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004105 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004106 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4107 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4108 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004109 goto failed;
4110 }
4111
4112 if (cp->name_known) {
4113 e->name_state = NAME_KNOWN;
4114 list_del(&e->list);
4115 } else {
4116 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004117 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004118 }
4119
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004120 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4121 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004122
4123failed:
4124 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004125 return err;
4126}
4127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004128static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004129 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004130{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004131 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004132 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004133 int err;
4134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004135 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004136
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004137 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004138 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4139 MGMT_STATUS_INVALID_PARAMS,
4140 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004141
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004142 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004143
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004144 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4145 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004146 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004147 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004148 goto done;
4149 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004150
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004151 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4152 sk);
4153 status = MGMT_STATUS_SUCCESS;
4154
4155done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004156 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4157 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004159 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004160
4161 return err;
4162}
4163
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004164static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004165 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004166{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004167 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004168 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004169 int err;
4170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004171 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004172
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004173 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004174 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4175 MGMT_STATUS_INVALID_PARAMS,
4176 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004177
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004178 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004179
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004180 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4181 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004182 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004183 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004184 goto done;
4185 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004186
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004187 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4188 sk);
4189 status = MGMT_STATUS_SUCCESS;
4190
4191done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004192 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4193 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004194
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004195 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004196
4197 return err;
4198}
4199
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004200static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4201 u16 len)
4202{
4203 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004204 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004205 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004206 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004207
4208 BT_DBG("%s", hdev->name);
4209
Szymon Jancc72d4b82012-03-16 16:02:57 +01004210 source = __le16_to_cpu(cp->source);
4211
4212 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004213 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4214 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004215
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004216 hci_dev_lock(hdev);
4217
Szymon Jancc72d4b82012-03-16 16:02:57 +01004218 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004219 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4220 hdev->devid_product = __le16_to_cpu(cp->product);
4221 hdev->devid_version = __le16_to_cpu(cp->version);
4222
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004223 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4224 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004225
Johan Hedberg890ea892013-03-15 17:06:52 -05004226 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004227 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004228 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004229
4230 hci_dev_unlock(hdev);
4231
4232 return err;
4233}
4234
Arman Uguray24b4f382015-03-23 15:57:12 -07004235static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4236 u16 opcode)
4237{
4238 BT_DBG("status %d", status);
4239}
4240
Marcel Holtmann1904a852015-01-11 13:50:44 -08004241static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4242 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004243{
4244 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004245 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004246 u8 instance;
4247 struct adv_info *adv_instance;
4248 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004249
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304250 hci_dev_lock(hdev);
4251
Johan Hedberg4375f102013-09-25 13:26:10 +03004252 if (status) {
4253 u8 mgmt_err = mgmt_status(status);
4254
4255 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4256 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304257 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004258 }
4259
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004260 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004261 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004262 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004263 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004264
Johan Hedberg4375f102013-09-25 13:26:10 +03004265 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4266 &match);
4267
4268 new_settings(hdev, match.sk);
4269
4270 if (match.sk)
4271 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304272
Arman Uguray24b4f382015-03-23 15:57:12 -07004273 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004274 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004275 */
4276 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004277 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004278 goto unlock;
4279
Florian Grandel7816b822015-06-18 03:16:45 +02004280 instance = hdev->cur_adv_instance;
4281 if (!instance) {
4282 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4283 struct adv_info, list);
4284 if (!adv_instance)
4285 goto unlock;
4286
4287 instance = adv_instance->instance;
4288 }
4289
Arman Uguray24b4f382015-03-23 15:57:12 -07004290 hci_req_init(&req, hdev);
4291
Johan Hedbergf2252572015-11-18 12:49:20 +02004292 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004293
Florian Grandel7816b822015-06-18 03:16:45 +02004294 if (!err)
4295 err = hci_req_run(&req, enable_advertising_instance);
4296
4297 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004298 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004299
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304300unlock:
4301 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004302}
4303
Marcel Holtmann21b51872013-10-10 09:47:53 -07004304static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4305 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004306{
4307 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004308 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004309 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004310 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004311 int err;
4312
4313 BT_DBG("request for %s", hdev->name);
4314
Johan Hedberge6fe7982013-10-02 15:45:22 +03004315 status = mgmt_le_support(hdev);
4316 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004317 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4318 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004319
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004320 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004321 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4322 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004323
4324 hci_dev_lock(hdev);
4325
4326 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004327
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004328 /* The following conditions are ones which mean that we should
4329 * not do any HCI communication but directly send a mgmt
4330 * response to user space (after toggling the flag if
4331 * necessary).
4332 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004333 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004334 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4335 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004336 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004337 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004338 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004339 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004340
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004341 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004342 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004343 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004344 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004345 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004346 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004347 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004348 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004349 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004350 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004351 }
4352
4353 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4354 if (err < 0)
4355 goto unlock;
4356
4357 if (changed)
4358 err = new_settings(hdev, sk);
4359
4360 goto unlock;
4361 }
4362
Johan Hedberg333ae952015-03-17 13:48:47 +02004363 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4364 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004365 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4366 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004367 goto unlock;
4368 }
4369
4370 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4371 if (!cmd) {
4372 err = -ENOMEM;
4373 goto unlock;
4374 }
4375
4376 hci_req_init(&req, hdev);
4377
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004378 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004379 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004380 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004381 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004382
Florian Grandel7816b822015-06-18 03:16:45 +02004383 cancel_adv_timeout(hdev);
4384
Arman Uguray24b4f382015-03-23 15:57:12 -07004385 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004386 /* Switch to instance "0" for the Set Advertising setting.
4387 * We cannot use update_[adv|scan_rsp]_data() here as the
4388 * HCI_ADVERTISING flag is not yet set.
4389 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004390 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304391
4392 if (ext_adv_capable(hdev)) {
4393 __hci_req_start_ext_adv(&req, 0x00);
4394 } else {
4395 __hci_req_update_adv_data(&req, 0x00);
4396 __hci_req_update_scan_rsp_data(&req, 0x00);
4397 __hci_req_enable_advertising(&req);
4398 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004399 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004400 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004401 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004402
4403 err = hci_req_run(&req, set_advertising_complete);
4404 if (err < 0)
4405 mgmt_pending_remove(cmd);
4406
4407unlock:
4408 hci_dev_unlock(hdev);
4409 return err;
4410}
4411
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004412static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4413 void *data, u16 len)
4414{
4415 struct mgmt_cp_set_static_address *cp = data;
4416 int err;
4417
4418 BT_DBG("%s", hdev->name);
4419
Marcel Holtmann62af4442013-10-02 22:10:32 -07004420 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004421 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4422 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004423
4424 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004425 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4426 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004427
4428 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4429 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004430 return mgmt_cmd_status(sk, hdev->id,
4431 MGMT_OP_SET_STATIC_ADDRESS,
4432 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004433
4434 /* Two most significant bits shall be set */
4435 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004436 return mgmt_cmd_status(sk, hdev->id,
4437 MGMT_OP_SET_STATIC_ADDRESS,
4438 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004439 }
4440
4441 hci_dev_lock(hdev);
4442
4443 bacpy(&hdev->static_addr, &cp->bdaddr);
4444
Marcel Holtmann93690c22015-03-06 10:11:21 -08004445 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4446 if (err < 0)
4447 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004448
Marcel Holtmann93690c22015-03-06 10:11:21 -08004449 err = new_settings(hdev, sk);
4450
4451unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004452 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004453 return err;
4454}
4455
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004456static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4457 void *data, u16 len)
4458{
4459 struct mgmt_cp_set_scan_params *cp = data;
4460 __u16 interval, window;
4461 int err;
4462
4463 BT_DBG("%s", hdev->name);
4464
4465 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004466 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4467 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004468
4469 interval = __le16_to_cpu(cp->interval);
4470
4471 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004472 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4473 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004474
4475 window = __le16_to_cpu(cp->window);
4476
4477 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004478 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4479 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004480
Marcel Holtmann899e1072013-10-14 09:55:32 -07004481 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004482 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4483 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004484
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004485 hci_dev_lock(hdev);
4486
4487 hdev->le_scan_interval = interval;
4488 hdev->le_scan_window = window;
4489
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004490 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4491 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004492
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004493 /* If background scan is running, restart it so new parameters are
4494 * loaded.
4495 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004496 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004497 hdev->discovery.state == DISCOVERY_STOPPED) {
4498 struct hci_request req;
4499
4500 hci_req_init(&req, hdev);
4501
4502 hci_req_add_le_scan_disable(&req);
4503 hci_req_add_le_passive_scan(&req);
4504
4505 hci_req_run(&req, NULL);
4506 }
4507
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004508 hci_dev_unlock(hdev);
4509
4510 return err;
4511}
4512
Marcel Holtmann1904a852015-01-11 13:50:44 -08004513static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4514 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004515{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004516 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004517
4518 BT_DBG("status 0x%02x", status);
4519
4520 hci_dev_lock(hdev);
4521
Johan Hedberg333ae952015-03-17 13:48:47 +02004522 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004523 if (!cmd)
4524 goto unlock;
4525
4526 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004527 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4528 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004529 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004530 struct mgmt_mode *cp = cmd->param;
4531
4532 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004533 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004534 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004535 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004536
Johan Hedberg33e38b32013-03-15 17:07:05 -05004537 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4538 new_settings(hdev, cmd->sk);
4539 }
4540
4541 mgmt_pending_remove(cmd);
4542
4543unlock:
4544 hci_dev_unlock(hdev);
4545}
4546
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004547static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004548 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004549{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004550 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004551 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004552 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004553 int err;
4554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004555 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004556
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004557 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004558 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004559 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4560 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004561
Johan Hedberga7e80f22013-01-09 16:05:19 +02004562 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004563 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4564 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004565
Antti Julkuf6422ec2011-06-22 13:11:56 +03004566 hci_dev_lock(hdev);
4567
Johan Hedberg333ae952015-03-17 13:48:47 +02004568 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004569 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4570 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004571 goto unlock;
4572 }
4573
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004574 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004575 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4576 hdev);
4577 goto unlock;
4578 }
4579
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004580 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004581 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004582 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4583 hdev);
4584 new_settings(hdev, sk);
4585 goto unlock;
4586 }
4587
Johan Hedberg33e38b32013-03-15 17:07:05 -05004588 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4589 data, len);
4590 if (!cmd) {
4591 err = -ENOMEM;
4592 goto unlock;
4593 }
4594
4595 hci_req_init(&req, hdev);
4596
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004597 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004598
4599 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004600 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004601 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4602 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004603 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004604 }
4605
Johan Hedberg33e38b32013-03-15 17:07:05 -05004606unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004607 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004608
Antti Julkuf6422ec2011-06-22 13:11:56 +03004609 return err;
4610}
4611
Marcel Holtmann1904a852015-01-11 13:50:44 -08004612static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004613{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004614 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004615
4616 BT_DBG("status 0x%02x", status);
4617
4618 hci_dev_lock(hdev);
4619
Johan Hedberg333ae952015-03-17 13:48:47 +02004620 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004621 if (!cmd)
4622 goto unlock;
4623
4624 if (status) {
4625 u8 mgmt_err = mgmt_status(status);
4626
4627 /* We need to restore the flag if related HCI commands
4628 * failed.
4629 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004630 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004631
Johan Hedberga69e8372015-03-06 21:08:53 +02004632 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004633 } else {
4634 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4635 new_settings(hdev, cmd->sk);
4636 }
4637
4638 mgmt_pending_remove(cmd);
4639
4640unlock:
4641 hci_dev_unlock(hdev);
4642}
4643
4644static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4645{
4646 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004647 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004648 struct hci_request req;
4649 int err;
4650
4651 BT_DBG("request for %s", hdev->name);
4652
4653 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004654 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4655 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004656
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004657 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004658 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4659 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004660
4661 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004662 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4663 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004664
4665 hci_dev_lock(hdev);
4666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004667 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004668 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4669 goto unlock;
4670 }
4671
4672 if (!hdev_is_powered(hdev)) {
4673 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004674 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4675 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4676 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4677 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4678 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004679 }
4680
Marcel Holtmannce05d602015-03-13 02:11:03 -07004681 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004682
4683 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4684 if (err < 0)
4685 goto unlock;
4686
4687 err = new_settings(hdev, sk);
4688 goto unlock;
4689 }
4690
4691 /* Reject disabling when powered on */
4692 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004693 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4694 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004695 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004696 } else {
4697 /* When configuring a dual-mode controller to operate
4698 * with LE only and using a static address, then switching
4699 * BR/EDR back on is not allowed.
4700 *
4701 * Dual-mode controllers shall operate with the public
4702 * address as its identity address for BR/EDR and LE. So
4703 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004704 *
4705 * The same restrictions applies when secure connections
4706 * has been enabled. For BR/EDR this is a controller feature
4707 * while for LE it is a host stack feature. This means that
4708 * switching BR/EDR back on when secure connections has been
4709 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004710 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004711 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004712 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004713 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004714 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4715 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004716 goto unlock;
4717 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004718 }
4719
Johan Hedberg333ae952015-03-17 13:48:47 +02004720 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004721 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4722 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004723 goto unlock;
4724 }
4725
4726 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4727 if (!cmd) {
4728 err = -ENOMEM;
4729 goto unlock;
4730 }
4731
Johan Hedbergf2252572015-11-18 12:49:20 +02004732 /* We need to flip the bit already here so that
4733 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004734 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004735 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004736
4737 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004738
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004739 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004740 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004741
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004742 /* Since only the advertising data flags will change, there
4743 * is no need to update the scan response data.
4744 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004745 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004746
Johan Hedberg0663ca22013-10-02 13:43:14 +03004747 err = hci_req_run(&req, set_bredr_complete);
4748 if (err < 0)
4749 mgmt_pending_remove(cmd);
4750
4751unlock:
4752 hci_dev_unlock(hdev);
4753 return err;
4754}
4755
Johan Hedberga1443f52015-01-23 15:42:46 +02004756static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4757{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004758 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004759 struct mgmt_mode *cp;
4760
4761 BT_DBG("%s status %u", hdev->name, status);
4762
4763 hci_dev_lock(hdev);
4764
Johan Hedberg333ae952015-03-17 13:48:47 +02004765 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004766 if (!cmd)
4767 goto unlock;
4768
4769 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004770 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4771 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004772 goto remove;
4773 }
4774
4775 cp = cmd->param;
4776
4777 switch (cp->val) {
4778 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004779 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4780 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004781 break;
4782 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004783 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004784 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004785 break;
4786 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004787 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4788 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004789 break;
4790 }
4791
4792 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4793 new_settings(hdev, cmd->sk);
4794
4795remove:
4796 mgmt_pending_remove(cmd);
4797unlock:
4798 hci_dev_unlock(hdev);
4799}
4800
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004801static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4802 void *data, u16 len)
4803{
4804 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004805 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004806 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004807 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004808 int err;
4809
4810 BT_DBG("request for %s", hdev->name);
4811
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004812 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004813 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004814 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4815 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004816
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004817 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004818 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004819 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004820 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4821 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004822
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004823 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004824 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004825 MGMT_STATUS_INVALID_PARAMS);
4826
4827 hci_dev_lock(hdev);
4828
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004829 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004830 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004831 bool changed;
4832
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004833 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004834 changed = !hci_dev_test_and_set_flag(hdev,
4835 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004836 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004837 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004838 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004839 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004840 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004841 changed = hci_dev_test_and_clear_flag(hdev,
4842 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004843 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004844 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004845
4846 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4847 if (err < 0)
4848 goto failed;
4849
4850 if (changed)
4851 err = new_settings(hdev, sk);
4852
4853 goto failed;
4854 }
4855
Johan Hedberg333ae952015-03-17 13:48:47 +02004856 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004857 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4858 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004859 goto failed;
4860 }
4861
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004862 val = !!cp->val;
4863
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004864 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4865 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004866 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4867 goto failed;
4868 }
4869
4870 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4871 if (!cmd) {
4872 err = -ENOMEM;
4873 goto failed;
4874 }
4875
Johan Hedberga1443f52015-01-23 15:42:46 +02004876 hci_req_init(&req, hdev);
4877 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4878 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004879 if (err < 0) {
4880 mgmt_pending_remove(cmd);
4881 goto failed;
4882 }
4883
4884failed:
4885 hci_dev_unlock(hdev);
4886 return err;
4887}
4888
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004889static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4890 void *data, u16 len)
4891{
4892 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004893 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004894 int err;
4895
4896 BT_DBG("request for %s", hdev->name);
4897
Johan Hedbergb97109792014-06-24 14:00:28 +03004898 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004899 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4900 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004901
4902 hci_dev_lock(hdev);
4903
4904 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004905 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004906 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004907 changed = hci_dev_test_and_clear_flag(hdev,
4908 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004909
Johan Hedbergb97109792014-06-24 14:00:28 +03004910 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004911 use_changed = !hci_dev_test_and_set_flag(hdev,
4912 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004913 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004914 use_changed = hci_dev_test_and_clear_flag(hdev,
4915 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004916
4917 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004918 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004919 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4920 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4921 sizeof(mode), &mode);
4922 }
4923
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004924 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4925 if (err < 0)
4926 goto unlock;
4927
4928 if (changed)
4929 err = new_settings(hdev, sk);
4930
4931unlock:
4932 hci_dev_unlock(hdev);
4933 return err;
4934}
4935
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004936static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4937 u16 len)
4938{
4939 struct mgmt_cp_set_privacy *cp = cp_data;
4940 bool changed;
4941 int err;
4942
4943 BT_DBG("request for %s", hdev->name);
4944
4945 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004946 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4947 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004948
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004949 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004950 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4951 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004952
4953 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004954 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4955 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004956
4957 hci_dev_lock(hdev);
4958
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004959 /* If user space supports this command it is also expected to
4960 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4961 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004962 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004963
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004964 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004965 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004966 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004967 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05304968 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004969 if (cp->privacy == 0x02)
4970 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4971 else
4972 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004973 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004974 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004975 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004976 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05304977 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004978 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004979 }
4980
4981 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4982 if (err < 0)
4983 goto unlock;
4984
4985 if (changed)
4986 err = new_settings(hdev, sk);
4987
4988unlock:
4989 hci_dev_unlock(hdev);
4990 return err;
4991}
4992
Johan Hedberg41edf162014-02-18 10:19:35 +02004993static bool irk_is_valid(struct mgmt_irk_info *irk)
4994{
4995 switch (irk->addr.type) {
4996 case BDADDR_LE_PUBLIC:
4997 return true;
4998
4999 case BDADDR_LE_RANDOM:
5000 /* Two most significant bits shall be set */
5001 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5002 return false;
5003 return true;
5004 }
5005
5006 return false;
5007}
5008
5009static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5010 u16 len)
5011{
5012 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005013 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5014 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005015 u16 irk_count, expected_len;
5016 int i, err;
5017
5018 BT_DBG("request for %s", hdev->name);
5019
5020 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005021 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5022 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005023
5024 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005025 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005026 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5027 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005028 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5029 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005030 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005031
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005032 expected_len = struct_size(cp, irks, irk_count);
Johan Hedberg41edf162014-02-18 10:19:35 +02005033 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005034 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5035 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005036 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5037 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005038 }
5039
5040 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5041
5042 for (i = 0; i < irk_count; i++) {
5043 struct mgmt_irk_info *key = &cp->irks[i];
5044
5045 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005046 return mgmt_cmd_status(sk, hdev->id,
5047 MGMT_OP_LOAD_IRKS,
5048 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005049 }
5050
5051 hci_dev_lock(hdev);
5052
5053 hci_smp_irks_clear(hdev);
5054
5055 for (i = 0; i < irk_count; i++) {
5056 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005057
Johan Hedberg85813a72015-10-21 18:02:59 +03005058 hci_add_irk(hdev, &irk->addr.bdaddr,
5059 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005060 BDADDR_ANY);
5061 }
5062
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005063 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005064
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005065 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005066
5067 hci_dev_unlock(hdev);
5068
5069 return err;
5070}
5071
Johan Hedberg3f706b72013-01-20 14:27:16 +02005072static bool ltk_is_valid(struct mgmt_ltk_info *key)
5073{
5074 if (key->master != 0x00 && key->master != 0x01)
5075 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005076
5077 switch (key->addr.type) {
5078 case BDADDR_LE_PUBLIC:
5079 return true;
5080
5081 case BDADDR_LE_RANDOM:
5082 /* Two most significant bits shall be set */
5083 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5084 return false;
5085 return true;
5086 }
5087
5088 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005089}
5090
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005091static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005092 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005093{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005094 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005095 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5096 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005097 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005098 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005099
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005100 BT_DBG("request for %s", hdev->name);
5101
5102 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005103 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5104 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005105
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005106 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005107 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005108 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5109 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005110 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5111 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005112 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005113
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005114 expected_len = struct_size(cp, keys, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005115 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005116 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5117 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005118 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5119 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005120 }
5121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005122 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005123
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005124 for (i = 0; i < key_count; i++) {
5125 struct mgmt_ltk_info *key = &cp->keys[i];
5126
Johan Hedberg3f706b72013-01-20 14:27:16 +02005127 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005128 return mgmt_cmd_status(sk, hdev->id,
5129 MGMT_OP_LOAD_LONG_TERM_KEYS,
5130 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005131 }
5132
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005133 hci_dev_lock(hdev);
5134
5135 hci_smp_ltks_clear(hdev);
5136
5137 for (i = 0; i < key_count; i++) {
5138 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005139 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005140
Johan Hedberg61b43352014-05-29 19:36:53 +03005141 switch (key->type) {
5142 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005143 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005144 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005145 break;
5146 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005147 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005148 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005149 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005150 case MGMT_LTK_P256_UNAUTH:
5151 authenticated = 0x00;
5152 type = SMP_LTK_P256;
5153 break;
5154 case MGMT_LTK_P256_AUTH:
5155 authenticated = 0x01;
5156 type = SMP_LTK_P256;
5157 break;
5158 case MGMT_LTK_P256_DEBUG:
5159 authenticated = 0x00;
5160 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005161 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005162 default:
5163 continue;
5164 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005165
Johan Hedberg85813a72015-10-21 18:02:59 +03005166 hci_add_ltk(hdev, &key->addr.bdaddr,
5167 le_addr_type(key->addr.type), type, authenticated,
5168 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005169 }
5170
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005171 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005172 NULL, 0);
5173
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005174 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005175
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005176 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005177}
5178
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005179static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005180{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005181 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005182 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005183 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005184
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005185 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005186
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005187 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005188 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005189 rp.tx_power = conn->tx_power;
5190 rp.max_tx_power = conn->max_tx_power;
5191 } else {
5192 rp.rssi = HCI_RSSI_INVALID;
5193 rp.tx_power = HCI_TX_POWER_INVALID;
5194 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005195 }
5196
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005197 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5198 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005199
5200 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005201 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005202
5203 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005204}
5205
Marcel Holtmann1904a852015-01-11 13:50:44 -08005206static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5207 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005208{
5209 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005210 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005211 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005212 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005213 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005214
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005215 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005216
5217 hci_dev_lock(hdev);
5218
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005219 /* Commands sent in request are either Read RSSI or Read Transmit Power
5220 * Level so we check which one was last sent to retrieve connection
5221 * handle. Both commands have handle as first parameter so it's safe to
5222 * cast data on the same command struct.
5223 *
5224 * First command sent is always Read RSSI and we fail only if it fails.
5225 * In other case we simply override error to indicate success as we
5226 * already remembered if TX power value is actually valid.
5227 */
5228 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5229 if (!cp) {
5230 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005231 status = MGMT_STATUS_SUCCESS;
5232 } else {
5233 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005234 }
5235
5236 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005237 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005238 goto unlock;
5239 }
5240
5241 handle = __le16_to_cpu(cp->handle);
5242 conn = hci_conn_hash_lookup_handle(hdev, handle);
5243 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005244 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5245 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005246 goto unlock;
5247 }
5248
Johan Hedberg333ae952015-03-17 13:48:47 +02005249 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005250 if (!cmd)
5251 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005252
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005253 cmd->cmd_complete(cmd, status);
5254 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005255
5256unlock:
5257 hci_dev_unlock(hdev);
5258}
5259
5260static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5261 u16 len)
5262{
5263 struct mgmt_cp_get_conn_info *cp = data;
5264 struct mgmt_rp_get_conn_info rp;
5265 struct hci_conn *conn;
5266 unsigned long conn_info_age;
5267 int err = 0;
5268
5269 BT_DBG("%s", hdev->name);
5270
5271 memset(&rp, 0, sizeof(rp));
5272 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5273 rp.addr.type = cp->addr.type;
5274
5275 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005276 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5277 MGMT_STATUS_INVALID_PARAMS,
5278 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005279
5280 hci_dev_lock(hdev);
5281
5282 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005283 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5284 MGMT_STATUS_NOT_POWERED, &rp,
5285 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005286 goto unlock;
5287 }
5288
5289 if (cp->addr.type == BDADDR_BREDR)
5290 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5291 &cp->addr.bdaddr);
5292 else
5293 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5294
5295 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005296 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5297 MGMT_STATUS_NOT_CONNECTED, &rp,
5298 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005299 goto unlock;
5300 }
5301
Johan Hedberg333ae952015-03-17 13:48:47 +02005302 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005303 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5304 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005305 goto unlock;
5306 }
5307
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005308 /* To avoid client trying to guess when to poll again for information we
5309 * calculate conn info age as random value between min/max set in hdev.
5310 */
5311 conn_info_age = hdev->conn_info_min_age +
5312 prandom_u32_max(hdev->conn_info_max_age -
5313 hdev->conn_info_min_age);
5314
5315 /* Query controller to refresh cached values if they are too old or were
5316 * never read.
5317 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005318 if (time_after(jiffies, conn->conn_info_timestamp +
5319 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005320 !conn->conn_info_timestamp) {
5321 struct hci_request req;
5322 struct hci_cp_read_tx_power req_txp_cp;
5323 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005324 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005325
5326 hci_req_init(&req, hdev);
5327 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5328 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5329 &req_rssi_cp);
5330
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005331 /* For LE links TX power does not change thus we don't need to
5332 * query for it once value is known.
5333 */
5334 if (!bdaddr_type_is_le(cp->addr.type) ||
5335 conn->tx_power == HCI_TX_POWER_INVALID) {
5336 req_txp_cp.handle = cpu_to_le16(conn->handle);
5337 req_txp_cp.type = 0x00;
5338 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5339 sizeof(req_txp_cp), &req_txp_cp);
5340 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005341
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005342 /* Max TX power needs to be read only once per connection */
5343 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5344 req_txp_cp.handle = cpu_to_le16(conn->handle);
5345 req_txp_cp.type = 0x01;
5346 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5347 sizeof(req_txp_cp), &req_txp_cp);
5348 }
5349
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005350 err = hci_req_run(&req, conn_info_refresh_complete);
5351 if (err < 0)
5352 goto unlock;
5353
5354 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5355 data, len);
5356 if (!cmd) {
5357 err = -ENOMEM;
5358 goto unlock;
5359 }
5360
5361 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005362 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005363 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005364
5365 conn->conn_info_timestamp = jiffies;
5366 } else {
5367 /* Cache is valid, just reply with values cached in hci_conn */
5368 rp.rssi = conn->rssi;
5369 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005370 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005371
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005372 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5373 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005374 }
5375
5376unlock:
5377 hci_dev_unlock(hdev);
5378 return err;
5379}
5380
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005381static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005382{
5383 struct hci_conn *conn = cmd->user_data;
5384 struct mgmt_rp_get_clock_info rp;
5385 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005386 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005387
5388 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005389 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005390
5391 if (status)
5392 goto complete;
5393
5394 hdev = hci_dev_get(cmd->index);
5395 if (hdev) {
5396 rp.local_clock = cpu_to_le32(hdev->clock);
5397 hci_dev_put(hdev);
5398 }
5399
5400 if (conn) {
5401 rp.piconet_clock = cpu_to_le32(conn->clock);
5402 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5403 }
5404
5405complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005406 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5407 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005408
5409 if (conn) {
5410 hci_conn_drop(conn);
5411 hci_conn_put(conn);
5412 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005413
5414 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005415}
5416
Marcel Holtmann1904a852015-01-11 13:50:44 -08005417static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005418{
Johan Hedberg95868422014-06-28 17:54:07 +03005419 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005420 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005421 struct hci_conn *conn;
5422
5423 BT_DBG("%s status %u", hdev->name, status);
5424
5425 hci_dev_lock(hdev);
5426
5427 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5428 if (!hci_cp)
5429 goto unlock;
5430
5431 if (hci_cp->which) {
5432 u16 handle = __le16_to_cpu(hci_cp->handle);
5433 conn = hci_conn_hash_lookup_handle(hdev, handle);
5434 } else {
5435 conn = NULL;
5436 }
5437
Johan Hedberg333ae952015-03-17 13:48:47 +02005438 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005439 if (!cmd)
5440 goto unlock;
5441
Johan Hedberg69487372014-12-05 13:36:07 +02005442 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005443 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005444
5445unlock:
5446 hci_dev_unlock(hdev);
5447}
5448
5449static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5450 u16 len)
5451{
5452 struct mgmt_cp_get_clock_info *cp = data;
5453 struct mgmt_rp_get_clock_info rp;
5454 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005455 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005456 struct hci_request req;
5457 struct hci_conn *conn;
5458 int err;
5459
5460 BT_DBG("%s", hdev->name);
5461
5462 memset(&rp, 0, sizeof(rp));
5463 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5464 rp.addr.type = cp->addr.type;
5465
5466 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005467 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5468 MGMT_STATUS_INVALID_PARAMS,
5469 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005470
5471 hci_dev_lock(hdev);
5472
5473 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005474 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5475 MGMT_STATUS_NOT_POWERED, &rp,
5476 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005477 goto unlock;
5478 }
5479
5480 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5481 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5482 &cp->addr.bdaddr);
5483 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005484 err = mgmt_cmd_complete(sk, hdev->id,
5485 MGMT_OP_GET_CLOCK_INFO,
5486 MGMT_STATUS_NOT_CONNECTED,
5487 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005488 goto unlock;
5489 }
5490 } else {
5491 conn = NULL;
5492 }
5493
5494 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5495 if (!cmd) {
5496 err = -ENOMEM;
5497 goto unlock;
5498 }
5499
Johan Hedberg69487372014-12-05 13:36:07 +02005500 cmd->cmd_complete = clock_info_cmd_complete;
5501
Johan Hedberg95868422014-06-28 17:54:07 +03005502 hci_req_init(&req, hdev);
5503
5504 memset(&hci_cp, 0, sizeof(hci_cp));
5505 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5506
5507 if (conn) {
5508 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005509 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005510
5511 hci_cp.handle = cpu_to_le16(conn->handle);
5512 hci_cp.which = 0x01; /* Piconet clock */
5513 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5514 }
5515
5516 err = hci_req_run(&req, get_clock_info_complete);
5517 if (err < 0)
5518 mgmt_pending_remove(cmd);
5519
5520unlock:
5521 hci_dev_unlock(hdev);
5522 return err;
5523}
5524
Johan Hedberg5a154e62014-12-19 22:26:02 +02005525static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5526{
5527 struct hci_conn *conn;
5528
5529 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5530 if (!conn)
5531 return false;
5532
5533 if (conn->dst_type != type)
5534 return false;
5535
5536 if (conn->state != BT_CONNECTED)
5537 return false;
5538
5539 return true;
5540}
5541
5542/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005543static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005544 u8 addr_type, u8 auto_connect)
5545{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005546 struct hci_conn_params *params;
5547
5548 params = hci_conn_params_add(hdev, addr, addr_type);
5549 if (!params)
5550 return -EIO;
5551
5552 if (params->auto_connect == auto_connect)
5553 return 0;
5554
5555 list_del_init(&params->action);
5556
5557 switch (auto_connect) {
5558 case HCI_AUTO_CONN_DISABLED:
5559 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005560 /* If auto connect is being disabled when we're trying to
5561 * connect to device, keep connecting.
5562 */
5563 if (params->explicit_connect)
5564 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005565 break;
5566 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005567 if (params->explicit_connect)
5568 list_add(&params->action, &hdev->pend_le_conns);
5569 else
5570 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005571 break;
5572 case HCI_AUTO_CONN_DIRECT:
5573 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005574 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005575 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005576 break;
5577 }
5578
5579 params->auto_connect = auto_connect;
5580
5581 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5582 auto_connect);
5583
5584 return 0;
5585}
5586
Marcel Holtmann8afef092014-06-29 22:28:34 +02005587static void device_added(struct sock *sk, struct hci_dev *hdev,
5588 bdaddr_t *bdaddr, u8 type, u8 action)
5589{
5590 struct mgmt_ev_device_added ev;
5591
5592 bacpy(&ev.addr.bdaddr, bdaddr);
5593 ev.addr.type = type;
5594 ev.action = action;
5595
5596 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5597}
5598
Marcel Holtmann2faade52014-06-29 19:44:03 +02005599static int add_device(struct sock *sk, struct hci_dev *hdev,
5600 void *data, u16 len)
5601{
5602 struct mgmt_cp_add_device *cp = data;
5603 u8 auto_conn, addr_type;
5604 int err;
5605
5606 BT_DBG("%s", hdev->name);
5607
Johan Hedberg66593582014-07-09 12:59:14 +03005608 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005609 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5611 MGMT_STATUS_INVALID_PARAMS,
5612 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005613
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005614 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005615 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5616 MGMT_STATUS_INVALID_PARAMS,
5617 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005618
5619 hci_dev_lock(hdev);
5620
Johan Hedberg66593582014-07-09 12:59:14 +03005621 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005622 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005623 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005624 err = mgmt_cmd_complete(sk, hdev->id,
5625 MGMT_OP_ADD_DEVICE,
5626 MGMT_STATUS_INVALID_PARAMS,
5627 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005628 goto unlock;
5629 }
5630
5631 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5632 cp->addr.type);
5633 if (err)
5634 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005635
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005636 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005637
Johan Hedberg66593582014-07-09 12:59:14 +03005638 goto added;
5639 }
5640
Johan Hedberg85813a72015-10-21 18:02:59 +03005641 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005642
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005643 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005644 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005645 else if (cp->action == 0x01)
5646 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005647 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005648 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005649
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005650 /* Kernel internally uses conn_params with resolvable private
5651 * address, but Add Device allows only identity addresses.
5652 * Make sure it is enforced before calling
5653 * hci_conn_params_lookup.
5654 */
5655 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005656 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5657 MGMT_STATUS_INVALID_PARAMS,
5658 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005659 goto unlock;
5660 }
5661
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005662 /* If the connection parameters don't exist for this device,
5663 * they will be created and configured with defaults.
5664 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005665 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005666 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005667 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5668 MGMT_STATUS_FAILED, &cp->addr,
5669 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005670 goto unlock;
5671 }
5672
Johan Hedberg51d7a942015-11-11 08:11:18 +02005673 hci_update_background_scan(hdev);
5674
Johan Hedberg66593582014-07-09 12:59:14 +03005675added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005676 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5677
Johan Hedberg51d7a942015-11-11 08:11:18 +02005678 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5679 MGMT_STATUS_SUCCESS, &cp->addr,
5680 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005681
5682unlock:
5683 hci_dev_unlock(hdev);
5684 return err;
5685}
5686
Marcel Holtmann8afef092014-06-29 22:28:34 +02005687static void device_removed(struct sock *sk, struct hci_dev *hdev,
5688 bdaddr_t *bdaddr, u8 type)
5689{
5690 struct mgmt_ev_device_removed ev;
5691
5692 bacpy(&ev.addr.bdaddr, bdaddr);
5693 ev.addr.type = type;
5694
5695 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5696}
5697
Marcel Holtmann2faade52014-06-29 19:44:03 +02005698static int remove_device(struct sock *sk, struct hci_dev *hdev,
5699 void *data, u16 len)
5700{
5701 struct mgmt_cp_remove_device *cp = data;
5702 int err;
5703
5704 BT_DBG("%s", hdev->name);
5705
5706 hci_dev_lock(hdev);
5707
5708 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005709 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005710 u8 addr_type;
5711
Johan Hedberg66593582014-07-09 12:59:14 +03005712 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005713 err = mgmt_cmd_complete(sk, hdev->id,
5714 MGMT_OP_REMOVE_DEVICE,
5715 MGMT_STATUS_INVALID_PARAMS,
5716 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005717 goto unlock;
5718 }
5719
Johan Hedberg66593582014-07-09 12:59:14 +03005720 if (cp->addr.type == BDADDR_BREDR) {
5721 err = hci_bdaddr_list_del(&hdev->whitelist,
5722 &cp->addr.bdaddr,
5723 cp->addr.type);
5724 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005725 err = mgmt_cmd_complete(sk, hdev->id,
5726 MGMT_OP_REMOVE_DEVICE,
5727 MGMT_STATUS_INVALID_PARAMS,
5728 &cp->addr,
5729 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005730 goto unlock;
5731 }
5732
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005733 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005734
Johan Hedberg66593582014-07-09 12:59:14 +03005735 device_removed(sk, hdev, &cp->addr.bdaddr,
5736 cp->addr.type);
5737 goto complete;
5738 }
5739
Johan Hedberg85813a72015-10-21 18:02:59 +03005740 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005741
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005742 /* Kernel internally uses conn_params with resolvable private
5743 * address, but Remove Device allows only identity addresses.
5744 * Make sure it is enforced before calling
5745 * hci_conn_params_lookup.
5746 */
5747 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005748 err = mgmt_cmd_complete(sk, hdev->id,
5749 MGMT_OP_REMOVE_DEVICE,
5750 MGMT_STATUS_INVALID_PARAMS,
5751 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005752 goto unlock;
5753 }
5754
Johan Hedbergc71593d2014-07-02 17:37:28 +03005755 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5756 addr_type);
5757 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005758 err = mgmt_cmd_complete(sk, hdev->id,
5759 MGMT_OP_REMOVE_DEVICE,
5760 MGMT_STATUS_INVALID_PARAMS,
5761 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005762 goto unlock;
5763 }
5764
Johan Hedberg679d2b62015-10-16 10:07:52 +03005765 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5766 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005767 err = mgmt_cmd_complete(sk, hdev->id,
5768 MGMT_OP_REMOVE_DEVICE,
5769 MGMT_STATUS_INVALID_PARAMS,
5770 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005771 goto unlock;
5772 }
5773
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005774 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005775 list_del(&params->list);
5776 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005777 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005778
5779 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005780 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005781 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005782 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005783
Marcel Holtmann2faade52014-06-29 19:44:03 +02005784 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005785 err = mgmt_cmd_complete(sk, hdev->id,
5786 MGMT_OP_REMOVE_DEVICE,
5787 MGMT_STATUS_INVALID_PARAMS,
5788 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005789 goto unlock;
5790 }
5791
Johan Hedberg66593582014-07-09 12:59:14 +03005792 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5793 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5794 list_del(&b->list);
5795 kfree(b);
5796 }
5797
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005798 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005799
Johan Hedberg19de0822014-07-06 13:06:51 +03005800 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5801 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5802 continue;
5803 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005804 if (p->explicit_connect) {
5805 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5806 continue;
5807 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005808 list_del(&p->action);
5809 list_del(&p->list);
5810 kfree(p);
5811 }
5812
5813 BT_DBG("All LE connection parameters were removed");
5814
Johan Hedberg51d7a942015-11-11 08:11:18 +02005815 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005816 }
5817
Johan Hedberg66593582014-07-09 12:59:14 +03005818complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005819 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5820 MGMT_STATUS_SUCCESS, &cp->addr,
5821 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005822unlock:
5823 hci_dev_unlock(hdev);
5824 return err;
5825}
5826
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005827static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5828 u16 len)
5829{
5830 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005831 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5832 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005833 u16 param_count, expected_len;
5834 int i;
5835
5836 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005837 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5838 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005839
5840 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005841 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005842 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
5843 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005844 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5845 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005846 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005847
Gustavo A. R. Silva5bec1fb2019-03-28 12:30:29 -05005848 expected_len = struct_size(cp, params, param_count);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005849 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005850 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
5851 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005852 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5853 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005854 }
5855
5856 BT_DBG("%s param_count %u", hdev->name, param_count);
5857
5858 hci_dev_lock(hdev);
5859
5860 hci_conn_params_clear_disabled(hdev);
5861
5862 for (i = 0; i < param_count; i++) {
5863 struct mgmt_conn_param *param = &cp->params[i];
5864 struct hci_conn_params *hci_param;
5865 u16 min, max, latency, timeout;
5866 u8 addr_type;
5867
5868 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5869 param->addr.type);
5870
5871 if (param->addr.type == BDADDR_LE_PUBLIC) {
5872 addr_type = ADDR_LE_DEV_PUBLIC;
5873 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5874 addr_type = ADDR_LE_DEV_RANDOM;
5875 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005876 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005877 continue;
5878 }
5879
5880 min = le16_to_cpu(param->min_interval);
5881 max = le16_to_cpu(param->max_interval);
5882 latency = le16_to_cpu(param->latency);
5883 timeout = le16_to_cpu(param->timeout);
5884
5885 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5886 min, max, latency, timeout);
5887
5888 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005889 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005890 continue;
5891 }
5892
5893 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5894 addr_type);
5895 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005896 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005897 continue;
5898 }
5899
5900 hci_param->conn_min_interval = min;
5901 hci_param->conn_max_interval = max;
5902 hci_param->conn_latency = latency;
5903 hci_param->supervision_timeout = timeout;
5904 }
5905
5906 hci_dev_unlock(hdev);
5907
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005908 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5909 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005910}
5911
Marcel Holtmanndbece372014-07-04 18:11:55 +02005912static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5913 void *data, u16 len)
5914{
5915 struct mgmt_cp_set_external_config *cp = data;
5916 bool changed;
5917 int err;
5918
5919 BT_DBG("%s", hdev->name);
5920
5921 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005922 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5923 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005924
5925 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005926 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5927 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005928
5929 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005930 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5931 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005932
5933 hci_dev_lock(hdev);
5934
5935 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005936 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005937 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005938 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005939
5940 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5941 if (err < 0)
5942 goto unlock;
5943
5944 if (!changed)
5945 goto unlock;
5946
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005947 err = new_options(hdev, sk);
5948
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005949 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005950 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005951
Marcel Holtmann516018a2015-03-13 02:11:04 -07005952 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005953 hci_dev_set_flag(hdev, HCI_CONFIG);
5954 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005955
5956 queue_work(hdev->req_workqueue, &hdev->power_on);
5957 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005958 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005959 mgmt_index_added(hdev);
5960 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005961 }
5962
5963unlock:
5964 hci_dev_unlock(hdev);
5965 return err;
5966}
5967
Marcel Holtmann9713c172014-07-06 12:11:15 +02005968static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5969 void *data, u16 len)
5970{
5971 struct mgmt_cp_set_public_address *cp = data;
5972 bool changed;
5973 int err;
5974
5975 BT_DBG("%s", hdev->name);
5976
5977 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005978 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5979 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005980
5981 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005982 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5983 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005984
5985 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005986 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5987 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005988
5989 hci_dev_lock(hdev);
5990
5991 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5992 bacpy(&hdev->public_addr, &cp->bdaddr);
5993
5994 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5995 if (err < 0)
5996 goto unlock;
5997
5998 if (!changed)
5999 goto unlock;
6000
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006001 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006002 err = new_options(hdev, sk);
6003
6004 if (is_configured(hdev)) {
6005 mgmt_index_removed(hdev);
6006
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006007 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006008
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006009 hci_dev_set_flag(hdev, HCI_CONFIG);
6010 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006011
6012 queue_work(hdev->req_workqueue, &hdev->power_on);
6013 }
6014
6015unlock:
6016 hci_dev_unlock(hdev);
6017 return err;
6018}
6019
Johan Hedberg40f66c02015-04-07 21:52:22 +03006020static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6021 u16 opcode, struct sk_buff *skb)
6022{
6023 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6024 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6025 u8 *h192, *r192, *h256, *r256;
6026 struct mgmt_pending_cmd *cmd;
6027 u16 eir_len;
6028 int err;
6029
6030 BT_DBG("%s status %u", hdev->name, status);
6031
6032 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6033 if (!cmd)
6034 return;
6035
6036 mgmt_cp = cmd->param;
6037
6038 if (status) {
6039 status = mgmt_status(status);
6040 eir_len = 0;
6041
6042 h192 = NULL;
6043 r192 = NULL;
6044 h256 = NULL;
6045 r256 = NULL;
6046 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6047 struct hci_rp_read_local_oob_data *rp;
6048
6049 if (skb->len != sizeof(*rp)) {
6050 status = MGMT_STATUS_FAILED;
6051 eir_len = 0;
6052 } else {
6053 status = MGMT_STATUS_SUCCESS;
6054 rp = (void *)skb->data;
6055
6056 eir_len = 5 + 18 + 18;
6057 h192 = rp->hash;
6058 r192 = rp->rand;
6059 h256 = NULL;
6060 r256 = NULL;
6061 }
6062 } else {
6063 struct hci_rp_read_local_oob_ext_data *rp;
6064
6065 if (skb->len != sizeof(*rp)) {
6066 status = MGMT_STATUS_FAILED;
6067 eir_len = 0;
6068 } else {
6069 status = MGMT_STATUS_SUCCESS;
6070 rp = (void *)skb->data;
6071
6072 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6073 eir_len = 5 + 18 + 18;
6074 h192 = NULL;
6075 r192 = NULL;
6076 } else {
6077 eir_len = 5 + 18 + 18 + 18 + 18;
6078 h192 = rp->hash192;
6079 r192 = rp->rand192;
6080 }
6081
6082 h256 = rp->hash256;
6083 r256 = rp->rand256;
6084 }
6085 }
6086
6087 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6088 if (!mgmt_rp)
6089 goto done;
6090
6091 if (status)
6092 goto send_rsp;
6093
6094 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6095 hdev->dev_class, 3);
6096
6097 if (h192 && r192) {
6098 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6099 EIR_SSP_HASH_C192, h192, 16);
6100 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6101 EIR_SSP_RAND_R192, r192, 16);
6102 }
6103
6104 if (h256 && r256) {
6105 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6106 EIR_SSP_HASH_C256, h256, 16);
6107 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6108 EIR_SSP_RAND_R256, r256, 16);
6109 }
6110
6111send_rsp:
6112 mgmt_rp->type = mgmt_cp->type;
6113 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6114
6115 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6116 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6117 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6118 if (err < 0 || status)
6119 goto done;
6120
6121 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6122
6123 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6124 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6125 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6126done:
6127 kfree(mgmt_rp);
6128 mgmt_pending_remove(cmd);
6129}
6130
6131static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6132 struct mgmt_cp_read_local_oob_ext_data *cp)
6133{
6134 struct mgmt_pending_cmd *cmd;
6135 struct hci_request req;
6136 int err;
6137
6138 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6139 cp, sizeof(*cp));
6140 if (!cmd)
6141 return -ENOMEM;
6142
6143 hci_req_init(&req, hdev);
6144
6145 if (bredr_sc_enabled(hdev))
6146 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6147 else
6148 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6149
6150 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6151 if (err < 0) {
6152 mgmt_pending_remove(cmd);
6153 return err;
6154 }
6155
6156 return 0;
6157}
6158
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006159static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6160 void *data, u16 data_len)
6161{
6162 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6163 struct mgmt_rp_read_local_oob_ext_data *rp;
6164 size_t rp_len;
6165 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006166 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006167 int err;
6168
6169 BT_DBG("%s", hdev->name);
6170
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006171 if (hdev_is_powered(hdev)) {
6172 switch (cp->type) {
6173 case BIT(BDADDR_BREDR):
6174 status = mgmt_bredr_support(hdev);
6175 if (status)
6176 eir_len = 0;
6177 else
6178 eir_len = 5;
6179 break;
6180 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6181 status = mgmt_le_support(hdev);
6182 if (status)
6183 eir_len = 0;
6184 else
6185 eir_len = 9 + 3 + 18 + 18 + 3;
6186 break;
6187 default:
6188 status = MGMT_STATUS_INVALID_PARAMS;
6189 eir_len = 0;
6190 break;
6191 }
6192 } else {
6193 status = MGMT_STATUS_NOT_POWERED;
6194 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006195 }
6196
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006197 rp_len = sizeof(*rp) + eir_len;
6198 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006199 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006200 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006201
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006202 if (status)
6203 goto complete;
6204
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006205 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006206
6207 eir_len = 0;
6208 switch (cp->type) {
6209 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006210 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6211 err = read_local_ssp_oob_req(hdev, sk, cp);
6212 hci_dev_unlock(hdev);
6213 if (!err)
6214 goto done;
6215
6216 status = MGMT_STATUS_FAILED;
6217 goto complete;
6218 } else {
6219 eir_len = eir_append_data(rp->eir, eir_len,
6220 EIR_CLASS_OF_DEV,
6221 hdev->dev_class, 3);
6222 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006223 break;
6224 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006225 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6226 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006227 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006228 status = MGMT_STATUS_FAILED;
6229 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006230 }
6231
Marcel Holtmanne2135682015-04-02 12:00:58 -07006232 /* This should return the active RPA, but since the RPA
6233 * is only programmed on demand, it is really hard to fill
6234 * this in at the moment. For now disallow retrieving
6235 * local out-of-band data when privacy is in use.
6236 *
6237 * Returning the identity address will not help here since
6238 * pairing happens before the identity resolving key is
6239 * known and thus the connection establishment happens
6240 * based on the RPA and not the identity address.
6241 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006242 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006243 hci_dev_unlock(hdev);
6244 status = MGMT_STATUS_REJECTED;
6245 goto complete;
6246 }
6247
6248 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6249 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6250 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6251 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006252 memcpy(addr, &hdev->static_addr, 6);
6253 addr[6] = 0x01;
6254 } else {
6255 memcpy(addr, &hdev->bdaddr, 6);
6256 addr[6] = 0x00;
6257 }
6258
6259 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6260 addr, sizeof(addr));
6261
6262 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6263 role = 0x02;
6264 else
6265 role = 0x01;
6266
6267 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6268 &role, sizeof(role));
6269
Marcel Holtmann5082a592015-03-16 12:39:00 -07006270 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6271 eir_len = eir_append_data(rp->eir, eir_len,
6272 EIR_LE_SC_CONFIRM,
6273 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006274
Marcel Holtmann5082a592015-03-16 12:39:00 -07006275 eir_len = eir_append_data(rp->eir, eir_len,
6276 EIR_LE_SC_RANDOM,
6277 rand, sizeof(rand));
6278 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006279
Johan Hedbergf2252572015-11-18 12:49:20 +02006280 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006281
6282 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6283 flags |= LE_AD_NO_BREDR;
6284
6285 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6286 &flags, sizeof(flags));
6287 break;
6288 }
6289
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006290 hci_dev_unlock(hdev);
6291
Marcel Holtmann72000df2015-03-16 16:11:21 -07006292 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6293
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006294 status = MGMT_STATUS_SUCCESS;
6295
6296complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006297 rp->type = cp->type;
6298 rp->eir_len = cpu_to_le16(eir_len);
6299
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006300 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006301 status, rp, sizeof(*rp) + eir_len);
6302 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006303 goto done;
6304
6305 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6306 rp, sizeof(*rp) + eir_len,
6307 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006308
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006309done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006310 kfree(rp);
6311
6312 return err;
6313}
6314
Arman Uguray089fa8c2015-03-25 18:53:45 -07006315static u32 get_supported_adv_flags(struct hci_dev *hdev)
6316{
6317 u32 flags = 0;
6318
6319 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6320 flags |= MGMT_ADV_FLAG_DISCOV;
6321 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6322 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006323 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006324 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006325
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306326 /* In extended adv TX_POWER returned from Set Adv Param
6327 * will be always valid.
6328 */
6329 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6330 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006331 flags |= MGMT_ADV_FLAG_TX_POWER;
6332
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306333 if (ext_adv_capable(hdev)) {
6334 flags |= MGMT_ADV_FLAG_SEC_1M;
6335
6336 if (hdev->le_features[1] & HCI_LE_PHY_2M)
6337 flags |= MGMT_ADV_FLAG_SEC_2M;
6338
6339 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
6340 flags |= MGMT_ADV_FLAG_SEC_CODED;
6341 }
6342
Arman Uguray089fa8c2015-03-25 18:53:45 -07006343 return flags;
6344}
6345
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006346static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6347 void *data, u16 data_len)
6348{
6349 struct mgmt_rp_read_adv_features *rp;
6350 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006351 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006352 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006353 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006354 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006355
6356 BT_DBG("%s", hdev->name);
6357
Arman Uguray089fa8c2015-03-25 18:53:45 -07006358 if (!lmp_le_capable(hdev))
6359 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6360 MGMT_STATUS_REJECTED);
6361
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006362 hci_dev_lock(hdev);
6363
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006364 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006365 rp = kmalloc(rp_len, GFP_ATOMIC);
6366 if (!rp) {
6367 hci_dev_unlock(hdev);
6368 return -ENOMEM;
6369 }
6370
Arman Uguray089fa8c2015-03-25 18:53:45 -07006371 supported_flags = get_supported_adv_flags(hdev);
6372
6373 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006374 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6375 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006376 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006377 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006378
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006379 instance = rp->instance;
6380 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6381 *instance = adv_instance->instance;
6382 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006383 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006384
6385 hci_dev_unlock(hdev);
6386
6387 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6388 MGMT_STATUS_SUCCESS, rp, rp_len);
6389
6390 kfree(rp);
6391
6392 return err;
6393}
6394
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006395static u8 calculate_name_len(struct hci_dev *hdev)
6396{
6397 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6398
6399 return append_local_name(hdev, buf, 0);
6400}
6401
6402static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6403 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006404{
Arman Uguray4117ed72015-03-23 15:57:14 -07006405 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006406
Marcel Holtmann31a32482015-11-19 16:16:42 +01006407 if (is_adv_data) {
6408 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6409 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006410 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006411 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006412
Szymon Janc2bb368702016-09-18 12:50:05 +02006413 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006414 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006415 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006416 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006417 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006418
Szymon Janc2bb368702016-09-18 12:50:05 +02006419 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006420 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006421 }
6422
Szymon Janc2bb368702016-09-18 12:50:05 +02006423 return max_len;
6424}
6425
6426static bool flags_managed(u32 adv_flags)
6427{
6428 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6429 MGMT_ADV_FLAG_LIMITED_DISCOV |
6430 MGMT_ADV_FLAG_MANAGED_FLAGS);
6431}
6432
6433static bool tx_power_managed(u32 adv_flags)
6434{
6435 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6436}
6437
6438static bool name_managed(u32 adv_flags)
6439{
6440 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6441}
6442
6443static bool appearance_managed(u32 adv_flags)
6444{
6445 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6446}
6447
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006448static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6449 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006450{
6451 int i, cur_len;
6452 u8 max_len;
6453
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006454 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02006455
Arman Uguray4117ed72015-03-23 15:57:14 -07006456 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006457 return false;
6458
Arman Uguray4117ed72015-03-23 15:57:14 -07006459 /* Make sure that the data is correctly formatted. */
6460 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6461 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006462
Szymon Janc9c9db782016-09-18 12:50:06 +02006463 if (data[i + 1] == EIR_FLAGS &&
6464 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006465 return false;
6466
Szymon Janc2bb368702016-09-18 12:50:05 +02006467 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6468 return false;
6469
6470 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6471 return false;
6472
6473 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6474 return false;
6475
6476 if (data[i + 1] == EIR_APPEARANCE &&
6477 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006478 return false;
6479
Arman Uguray24b4f382015-03-23 15:57:12 -07006480 /* If the current field length would exceed the total data
6481 * length, then it's invalid.
6482 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006483 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006484 return false;
6485 }
6486
6487 return true;
6488}
6489
Arman Uguray24b4f382015-03-23 15:57:12 -07006490static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6491 u16 opcode)
6492{
6493 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006494 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006495 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006496 struct adv_info *adv_instance, *n;
6497 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006498
6499 BT_DBG("status %d", status);
6500
6501 hci_dev_lock(hdev);
6502
6503 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6504
Florian Grandelfffd38b2015-06-18 03:16:47 +02006505 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6506 if (!adv_instance->pending)
6507 continue;
6508
6509 if (!status) {
6510 adv_instance->pending = false;
6511 continue;
6512 }
6513
6514 instance = adv_instance->instance;
6515
6516 if (hdev->cur_adv_instance == instance)
6517 cancel_adv_timeout(hdev);
6518
6519 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006520 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006521 }
6522
6523 if (!cmd)
6524 goto unlock;
6525
Florian Grandelfffd38b2015-06-18 03:16:47 +02006526 cp = cmd->param;
6527 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006528
6529 if (status)
6530 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6531 mgmt_status(status));
6532 else
6533 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6534 mgmt_status(status), &rp, sizeof(rp));
6535
6536 mgmt_pending_remove(cmd);
6537
6538unlock:
6539 hci_dev_unlock(hdev);
6540}
6541
6542static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6543 void *data, u16 data_len)
6544{
6545 struct mgmt_cp_add_advertising *cp = data;
6546 struct mgmt_rp_add_advertising rp;
6547 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306548 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006549 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006550 u16 timeout, duration;
6551 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6552 u8 schedule_instance = 0;
6553 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006554 int err;
6555 struct mgmt_pending_cmd *cmd;
6556 struct hci_request req;
6557
6558 BT_DBG("%s", hdev->name);
6559
6560 status = mgmt_le_support(hdev);
6561 if (status)
6562 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6563 status);
6564
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006565 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6567 MGMT_STATUS_INVALID_PARAMS);
6568
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006569 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6570 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6571 MGMT_STATUS_INVALID_PARAMS);
6572
Arman Uguray24b4f382015-03-23 15:57:12 -07006573 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006574 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006575 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006576
Florian Grandelfffd38b2015-06-18 03:16:47 +02006577 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306578 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006579 */
6580 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306581 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
6582 if (flags & ~supported_flags ||
6583 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07006584 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6585 MGMT_STATUS_INVALID_PARAMS);
6586
6587 hci_dev_lock(hdev);
6588
Arman Uguray912098a2015-03-23 15:57:15 -07006589 if (timeout && !hdev_is_powered(hdev)) {
6590 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6591 MGMT_STATUS_REJECTED);
6592 goto unlock;
6593 }
6594
Arman Uguray24b4f382015-03-23 15:57:12 -07006595 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006596 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006597 pending_find(MGMT_OP_SET_LE, hdev)) {
6598 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6599 MGMT_STATUS_BUSY);
6600 goto unlock;
6601 }
6602
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006603 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
6604 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006605 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006606 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6607 MGMT_STATUS_INVALID_PARAMS);
6608 goto unlock;
6609 }
6610
Florian Grandelfffd38b2015-06-18 03:16:47 +02006611 err = hci_add_adv_instance(hdev, cp->instance, flags,
6612 cp->adv_data_len, cp->data,
6613 cp->scan_rsp_len,
6614 cp->data + cp->adv_data_len,
6615 timeout, duration);
6616 if (err < 0) {
6617 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6618 MGMT_STATUS_FAILED);
6619 goto unlock;
6620 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006621
Florian Grandelfffd38b2015-06-18 03:16:47 +02006622 /* Only trigger an advertising added event if a new instance was
6623 * actually added.
6624 */
6625 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006626 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006627
Florian Grandelfffd38b2015-06-18 03:16:47 +02006628 if (hdev->cur_adv_instance == cp->instance) {
6629 /* If the currently advertised instance is being changed then
6630 * cancel the current advertising and schedule the next
6631 * instance. If there is only one instance then the overridden
6632 * advertising data will be visible right away.
6633 */
6634 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006635
Florian Grandelfffd38b2015-06-18 03:16:47 +02006636 next_instance = hci_get_next_instance(hdev, cp->instance);
6637 if (next_instance)
6638 schedule_instance = next_instance->instance;
6639 } else if (!hdev->adv_instance_timeout) {
6640 /* Immediately advertise the new instance if no other
6641 * instance is currently being advertised.
6642 */
6643 schedule_instance = cp->instance;
6644 }
Arman Uguray912098a2015-03-23 15:57:15 -07006645
Florian Grandelfffd38b2015-06-18 03:16:47 +02006646 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6647 * there is no instance to be advertised then we have no HCI
6648 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006649 */
6650 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006651 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6652 !schedule_instance) {
6653 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006654 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6655 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6656 goto unlock;
6657 }
6658
6659 /* We're good to go, update advertising data, parameters, and start
6660 * advertising.
6661 */
6662 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6663 data_len);
6664 if (!cmd) {
6665 err = -ENOMEM;
6666 goto unlock;
6667 }
6668
6669 hci_req_init(&req, hdev);
6670
Johan Hedbergf2252572015-11-18 12:49:20 +02006671 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006672
Florian Grandelfffd38b2015-06-18 03:16:47 +02006673 if (!err)
6674 err = hci_req_run(&req, add_advertising_complete);
6675
Arman Uguray24b4f382015-03-23 15:57:12 -07006676 if (err < 0)
6677 mgmt_pending_remove(cmd);
6678
6679unlock:
6680 hci_dev_unlock(hdev);
6681
6682 return err;
6683}
6684
Arman Ugurayda9293352015-03-23 15:57:13 -07006685static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6686 u16 opcode)
6687{
6688 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006689 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006690 struct mgmt_rp_remove_advertising rp;
6691
6692 BT_DBG("status %d", status);
6693
6694 hci_dev_lock(hdev);
6695
6696 /* A failure status here only means that we failed to disable
6697 * advertising. Otherwise, the advertising instance has been removed,
6698 * so report success.
6699 */
6700 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6701 if (!cmd)
6702 goto unlock;
6703
Florian Grandel01948332015-06-18 03:16:48 +02006704 cp = cmd->param;
6705 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006706
6707 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6708 &rp, sizeof(rp));
6709 mgmt_pending_remove(cmd);
6710
6711unlock:
6712 hci_dev_unlock(hdev);
6713}
6714
6715static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6716 void *data, u16 data_len)
6717{
6718 struct mgmt_cp_remove_advertising *cp = data;
6719 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006720 struct mgmt_pending_cmd *cmd;
6721 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006722 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006723
6724 BT_DBG("%s", hdev->name);
6725
Arman Ugurayda9293352015-03-23 15:57:13 -07006726 hci_dev_lock(hdev);
6727
Johan Hedberg952497b2015-06-18 21:05:31 +03006728 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006729 err = mgmt_cmd_status(sk, hdev->id,
6730 MGMT_OP_REMOVE_ADVERTISING,
6731 MGMT_STATUS_INVALID_PARAMS);
6732 goto unlock;
6733 }
6734
Arman Ugurayda9293352015-03-23 15:57:13 -07006735 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6736 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6737 pending_find(MGMT_OP_SET_LE, hdev)) {
6738 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6739 MGMT_STATUS_BUSY);
6740 goto unlock;
6741 }
6742
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006743 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006744 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6745 MGMT_STATUS_INVALID_PARAMS);
6746 goto unlock;
6747 }
6748
Florian Grandel01948332015-06-18 03:16:48 +02006749 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006750
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006751 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006752
Florian Grandel01948332015-06-18 03:16:48 +02006753 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006754 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006755
Florian Grandel01948332015-06-18 03:16:48 +02006756 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6757 * flag is set or the device isn't powered then we have no HCI
6758 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006759 */
Florian Grandel01948332015-06-18 03:16:48 +02006760 if (skb_queue_empty(&req.cmd_q) ||
6761 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006762 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05306763 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02006764 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006765 err = mgmt_cmd_complete(sk, hdev->id,
6766 MGMT_OP_REMOVE_ADVERTISING,
6767 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6768 goto unlock;
6769 }
6770
6771 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6772 data_len);
6773 if (!cmd) {
6774 err = -ENOMEM;
6775 goto unlock;
6776 }
6777
Arman Ugurayda9293352015-03-23 15:57:13 -07006778 err = hci_req_run(&req, remove_advertising_complete);
6779 if (err < 0)
6780 mgmt_pending_remove(cmd);
6781
6782unlock:
6783 hci_dev_unlock(hdev);
6784
6785 return err;
6786}
6787
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006788static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6789 void *data, u16 data_len)
6790{
6791 struct mgmt_cp_get_adv_size_info *cp = data;
6792 struct mgmt_rp_get_adv_size_info rp;
6793 u32 flags, supported_flags;
6794 int err;
6795
6796 BT_DBG("%s", hdev->name);
6797
6798 if (!lmp_le_capable(hdev))
6799 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6800 MGMT_STATUS_REJECTED);
6801
6802 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6803 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6804 MGMT_STATUS_INVALID_PARAMS);
6805
6806 flags = __le32_to_cpu(cp->flags);
6807
6808 /* The current implementation only supports a subset of the specified
6809 * flags.
6810 */
6811 supported_flags = get_supported_adv_flags(hdev);
6812 if (flags & ~supported_flags)
6813 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6814 MGMT_STATUS_INVALID_PARAMS);
6815
6816 rp.instance = cp->instance;
6817 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006818 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
6819 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006820
6821 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6822 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6823
6824 return err;
6825}
6826
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006827static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006828 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006829 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006830 HCI_MGMT_NO_HDEV |
6831 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006832 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006833 HCI_MGMT_NO_HDEV |
6834 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006835 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006836 HCI_MGMT_NO_HDEV |
6837 HCI_MGMT_UNTRUSTED },
6838 { read_controller_info, MGMT_READ_INFO_SIZE,
6839 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006840 { set_powered, MGMT_SETTING_SIZE },
6841 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6842 { set_connectable, MGMT_SETTING_SIZE },
6843 { set_fast_connectable, MGMT_SETTING_SIZE },
6844 { set_bondable, MGMT_SETTING_SIZE },
6845 { set_link_security, MGMT_SETTING_SIZE },
6846 { set_ssp, MGMT_SETTING_SIZE },
6847 { set_hs, MGMT_SETTING_SIZE },
6848 { set_le, MGMT_SETTING_SIZE },
6849 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6850 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6851 { add_uuid, MGMT_ADD_UUID_SIZE },
6852 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006853 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6854 HCI_MGMT_VAR_LEN },
6855 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6856 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006857 { disconnect, MGMT_DISCONNECT_SIZE },
6858 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6859 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6860 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6861 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6862 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6863 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6864 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6865 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6866 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6867 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6868 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006869 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6870 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6871 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006872 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6873 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6874 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6875 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6876 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6877 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6878 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6879 { set_advertising, MGMT_SETTING_SIZE },
6880 { set_bredr, MGMT_SETTING_SIZE },
6881 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6882 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6883 { set_secure_conn, MGMT_SETTING_SIZE },
6884 { set_debug_keys, MGMT_SETTING_SIZE },
6885 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006886 { load_irks, MGMT_LOAD_IRKS_SIZE,
6887 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006888 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6889 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6890 { add_device, MGMT_ADD_DEVICE_SIZE },
6891 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006892 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6893 HCI_MGMT_VAR_LEN },
6894 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006895 HCI_MGMT_NO_HDEV |
6896 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006897 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006898 HCI_MGMT_UNCONFIGURED |
6899 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006900 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6901 HCI_MGMT_UNCONFIGURED },
6902 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6903 HCI_MGMT_UNCONFIGURED },
6904 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6905 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006906 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006907 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006908 HCI_MGMT_NO_HDEV |
6909 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006910 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006911 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6912 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006913 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006914 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006915 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006916 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6917 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006918 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05306919 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05306920 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006921};
6922
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006923void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006924{
Marcel Holtmannced85542015-03-14 19:27:56 -07006925 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006926
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006927 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6928 return;
6929
Marcel Holtmannf9207332015-03-14 19:27:55 -07006930 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006931 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006932 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6933 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6934 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006935 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006936 } else {
6937 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6938 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006939 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006940 }
6941 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006942 case HCI_AMP:
6943 ev.type = 0x02;
6944 break;
6945 default:
6946 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006947 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006948
6949 ev.bus = hdev->bus;
6950
6951 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6952 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006953}
6954
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006955void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006956{
Marcel Holtmannced85542015-03-14 19:27:56 -07006957 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006958 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006959
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006960 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6961 return;
6962
Marcel Holtmannf9207332015-03-14 19:27:55 -07006963 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006964 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006965 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006966
Marcel Holtmannf9207332015-03-14 19:27:55 -07006967 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6968 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6969 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006970 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006971 } else {
6972 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6973 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006974 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006975 }
6976 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006977 case HCI_AMP:
6978 ev.type = 0x02;
6979 break;
6980 default:
6981 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006982 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006983
6984 ev.bus = hdev->bus;
6985
6986 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6987 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006988}
6989
Andre Guedes6046dc32014-02-26 20:21:51 -03006990/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006991static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006992{
6993 struct hci_conn_params *p;
6994
6995 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006996 /* Needed for AUTO_OFF case where might not "really"
6997 * have been powered off.
6998 */
6999 list_del_init(&p->action);
7000
7001 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007002 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007003 case HCI_AUTO_CONN_ALWAYS:
7004 list_add(&p->action, &hdev->pend_le_conns);
7005 break;
7006 case HCI_AUTO_CONN_REPORT:
7007 list_add(&p->action, &hdev->pend_le_reports);
7008 break;
7009 default:
7010 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007011 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007012 }
7013}
7014
Johan Hedberg2ff13892015-11-25 16:15:44 +02007015void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007016{
7017 struct cmd_lookup match = { NULL, hdev };
7018
Johan Hedberg2ff13892015-11-25 16:15:44 +02007019 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007020
Johan Hedberg2ff13892015-11-25 16:15:44 +02007021 hci_dev_lock(hdev);
7022
7023 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007024 restart_le_actions(hdev);
7025 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007026 }
7027
Johan Hedberg229ab392013-03-15 17:06:53 -05007028 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7029
7030 new_settings(hdev, match.sk);
7031
Johan Hedberg229ab392013-03-15 17:06:53 -05007032 if (match.sk)
7033 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007034
7035 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007036}
7037
Johan Hedberg2ff13892015-11-25 16:15:44 +02007038void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007039{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007040 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007041 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007042
Johan Hedberg229ab392013-03-15 17:06:53 -05007043 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007044
7045 /* If the power off is because of hdev unregistration let
7046 * use the appropriate INVALID_INDEX status. Otherwise use
7047 * NOT_POWERED. We cover both scenarios here since later in
7048 * mgmt_index_removed() any hci_conn callbacks will have already
7049 * been triggered, potentially causing misleading DISCONNECTED
7050 * status responses.
7051 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007052 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007053 status = MGMT_STATUS_INVALID_INDEX;
7054 else
7055 status = MGMT_STATUS_NOT_POWERED;
7056
7057 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007058
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007059 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007060 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7061 zero_cod, sizeof(zero_cod),
7062 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007063 ext_info_changed(hdev, NULL);
7064 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007065
Johan Hedberg2ff13892015-11-25 16:15:44 +02007066 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007067
7068 if (match.sk)
7069 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007070}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007071
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007072void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007073{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007074 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007075 u8 status;
7076
Johan Hedberg333ae952015-03-17 13:48:47 +02007077 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007078 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007079 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007080
7081 if (err == -ERFKILL)
7082 status = MGMT_STATUS_RFKILLED;
7083 else
7084 status = MGMT_STATUS_FAILED;
7085
Johan Hedberga69e8372015-03-06 21:08:53 +02007086 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007087
7088 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007089}
7090
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007091void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7092 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007093{
Johan Hedberg86742e12011-11-07 23:13:38 +02007094 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007095
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007096 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007097
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007098 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007099 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007100 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007101 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007102 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007103 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007104
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007105 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007106}
Johan Hedbergf7520542011-01-20 12:34:39 +02007107
Johan Hedbergd7b25452014-05-23 13:19:53 +03007108static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7109{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007110 switch (ltk->type) {
7111 case SMP_LTK:
7112 case SMP_LTK_SLAVE:
7113 if (ltk->authenticated)
7114 return MGMT_LTK_AUTHENTICATED;
7115 return MGMT_LTK_UNAUTHENTICATED;
7116 case SMP_LTK_P256:
7117 if (ltk->authenticated)
7118 return MGMT_LTK_P256_AUTH;
7119 return MGMT_LTK_P256_UNAUTH;
7120 case SMP_LTK_P256_DEBUG:
7121 return MGMT_LTK_P256_DEBUG;
7122 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007123
7124 return MGMT_LTK_UNAUTHENTICATED;
7125}
7126
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007127void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007128{
7129 struct mgmt_ev_new_long_term_key ev;
7130
7131 memset(&ev, 0, sizeof(ev));
7132
Marcel Holtmann5192d302014-02-19 17:11:58 -08007133 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007134 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007135 * to store long term keys. Their addresses will change the
7136 * next time around.
7137 *
7138 * Only when a remote device provides an identity address
7139 * make sure the long term key is stored. If the remote
7140 * identity is known, the long term keys are internally
7141 * mapped to the identity address. So allow static random
7142 * and public addresses here.
7143 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007144 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7145 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7146 ev.store_hint = 0x00;
7147 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007148 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007149
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007150 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007151 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007152 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007153 ev.key.enc_size = key->enc_size;
7154 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007155 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007156
Johan Hedberg2ceba532014-06-16 19:25:16 +03007157 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007158 ev.key.master = 1;
7159
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007160 /* Make sure we copy only the significant bytes based on the
7161 * encryption key size, and set the rest of the value to zeroes.
7162 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007163 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007164 memset(ev.key.val + key->enc_size, 0,
7165 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007166
Marcel Holtmann083368f2013-10-15 14:26:29 -07007167 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007168}
7169
Johan Hedbergcad20c22015-10-12 13:36:19 +02007170void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007171{
7172 struct mgmt_ev_new_irk ev;
7173
7174 memset(&ev, 0, sizeof(ev));
7175
Johan Hedbergcad20c22015-10-12 13:36:19 +02007176 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007177
Johan Hedberg95fbac82014-02-19 15:18:31 +02007178 bacpy(&ev.rpa, &irk->rpa);
7179 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7180 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7181 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7182
7183 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7184}
7185
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007186void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7187 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007188{
7189 struct mgmt_ev_new_csrk ev;
7190
7191 memset(&ev, 0, sizeof(ev));
7192
7193 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007194 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007195 * to store signature resolving keys. Their addresses will change
7196 * the next time around.
7197 *
7198 * Only when a remote device provides an identity address
7199 * make sure the signature resolving key is stored. So allow
7200 * static random and public addresses here.
7201 */
7202 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7203 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7204 ev.store_hint = 0x00;
7205 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007206 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007207
7208 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7209 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007210 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007211 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7212
7213 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7214}
7215
Andre Guedesffb5a8272014-07-01 18:10:11 -03007216void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007217 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7218 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007219{
7220 struct mgmt_ev_new_conn_param ev;
7221
Johan Hedbergc103aea2014-07-02 17:37:34 +03007222 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7223 return;
7224
Andre Guedesffb5a8272014-07-01 18:10:11 -03007225 memset(&ev, 0, sizeof(ev));
7226 bacpy(&ev.addr.bdaddr, bdaddr);
7227 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007228 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007229 ev.min_interval = cpu_to_le16(min_interval);
7230 ev.max_interval = cpu_to_le16(max_interval);
7231 ev.latency = cpu_to_le16(latency);
7232 ev.timeout = cpu_to_le16(timeout);
7233
7234 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7235}
7236
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007237void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7238 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007239{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007240 char buf[512];
7241 struct mgmt_ev_device_connected *ev = (void *) buf;
7242 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007243
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007244 bacpy(&ev->addr.bdaddr, &conn->dst);
7245 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007246
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007247 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007248
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007249 /* We must ensure that the EIR Data fields are ordered and
7250 * unique. Keep it simple for now and avoid the problem by not
7251 * adding any BR/EDR data to the LE adv.
7252 */
7253 if (conn->le_adv_data_len > 0) {
7254 memcpy(&ev->eir[eir_len],
7255 conn->le_adv_data, conn->le_adv_data_len);
7256 eir_len = conn->le_adv_data_len;
7257 } else {
7258 if (name_len > 0)
7259 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7260 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007261
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007262 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007263 eir_len = eir_append_data(ev->eir, eir_len,
7264 EIR_CLASS_OF_DEV,
7265 conn->dev_class, 3);
7266 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007267
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007268 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007269
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007270 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7271 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007272}
7273
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007274static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007275{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007276 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007277
Johan Hedbergf5818c22014-12-05 13:36:02 +02007278 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007279
7280 *sk = cmd->sk;
7281 sock_hold(*sk);
7282
Johan Hedberga664b5b2011-02-19 12:06:02 -03007283 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007284}
7285
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007286static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007287{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007288 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007289 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007290
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007291 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7292
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007293 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007294 mgmt_pending_remove(cmd);
7295}
7296
Johan Hedberg84c61d92014-08-01 11:13:30 +03007297bool mgmt_powering_down(struct hci_dev *hdev)
7298{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007299 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007300 struct mgmt_mode *cp;
7301
Johan Hedberg333ae952015-03-17 13:48:47 +02007302 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007303 if (!cmd)
7304 return false;
7305
7306 cp = cmd->param;
7307 if (!cp->val)
7308 return true;
7309
7310 return false;
7311}
7312
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007313void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007314 u8 link_type, u8 addr_type, u8 reason,
7315 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007316{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007317 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007318 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007319
Johan Hedberg84c61d92014-08-01 11:13:30 +03007320 /* The connection is still in hci_conn_hash so test for 1
7321 * instead of 0 to know if this is the last one.
7322 */
7323 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7324 cancel_delayed_work(&hdev->power_off);
7325 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007326 }
7327
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007328 if (!mgmt_connected)
7329 return;
7330
Andre Guedes57eb7762013-10-30 19:01:41 -03007331 if (link_type != ACL_LINK && link_type != LE_LINK)
7332 return;
7333
Johan Hedberg744cf192011-11-08 20:40:14 +02007334 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007335
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007336 bacpy(&ev.addr.bdaddr, bdaddr);
7337 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7338 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007339
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007340 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007341
7342 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007343 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007344
Johan Hedberg124f6e32012-02-09 13:50:12 +02007345 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007346 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007347}
7348
Marcel Holtmann78929242013-10-06 23:55:47 -07007349void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7350 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007351{
Andre Guedes3655bba2013-10-30 19:01:40 -03007352 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7353 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007354 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007355
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007356 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7357 hdev);
7358
Johan Hedberg333ae952015-03-17 13:48:47 +02007359 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007360 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007361 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007362
Andre Guedes3655bba2013-10-30 19:01:40 -03007363 cp = cmd->param;
7364
7365 if (bacmp(bdaddr, &cp->addr.bdaddr))
7366 return;
7367
7368 if (cp->addr.type != bdaddr_type)
7369 return;
7370
Johan Hedbergf5818c22014-12-05 13:36:02 +02007371 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007372 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007373}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007374
Marcel Holtmann445608d2013-10-06 23:55:48 -07007375void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7376 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007377{
7378 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007379
Johan Hedberg84c61d92014-08-01 11:13:30 +03007380 /* The connection is still in hci_conn_hash so test for 1
7381 * instead of 0 to know if this is the last one.
7382 */
7383 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7384 cancel_delayed_work(&hdev->power_off);
7385 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007386 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007387
Johan Hedberg4c659c32011-11-07 23:13:39 +02007388 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007389 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007390 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007391
Marcel Holtmann445608d2013-10-06 23:55:48 -07007392 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007393}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007394
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007395void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007396{
7397 struct mgmt_ev_pin_code_request ev;
7398
Johan Hedbergd8457692012-02-17 14:24:57 +02007399 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007400 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007401 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007402
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007403 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007404}
7405
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007406void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7407 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007408{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007409 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007410
Johan Hedberg333ae952015-03-17 13:48:47 +02007411 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007412 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007413 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007414
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007415 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007416 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007417}
7418
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007419void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7420 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007421{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007422 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007423
Johan Hedberg333ae952015-03-17 13:48:47 +02007424 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007425 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007426 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007427
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007428 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007429 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007430}
Johan Hedberga5c29682011-02-19 12:05:57 -03007431
Johan Hedberg744cf192011-11-08 20:40:14 +02007432int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007433 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007434 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007435{
7436 struct mgmt_ev_user_confirm_request ev;
7437
Johan Hedberg744cf192011-11-08 20:40:14 +02007438 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007439
Johan Hedberg272d90d2012-02-09 15:26:12 +02007440 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007441 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007442 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007443 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007444
Johan Hedberg744cf192011-11-08 20:40:14 +02007445 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007446 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007447}
7448
Johan Hedberg272d90d2012-02-09 15:26:12 +02007449int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007450 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007451{
7452 struct mgmt_ev_user_passkey_request ev;
7453
7454 BT_DBG("%s", hdev->name);
7455
Johan Hedberg272d90d2012-02-09 15:26:12 +02007456 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007457 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007458
7459 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007460 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007461}
7462
Brian Gix0df4c182011-11-16 13:53:13 -08007463static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007464 u8 link_type, u8 addr_type, u8 status,
7465 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007466{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007467 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007468
Johan Hedberg333ae952015-03-17 13:48:47 +02007469 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007470 if (!cmd)
7471 return -ENOENT;
7472
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007473 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007474 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007475
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007476 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007477}
7478
Johan Hedberg744cf192011-11-08 20:40:14 +02007479int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007480 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007481{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007482 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007483 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007484}
7485
Johan Hedberg272d90d2012-02-09 15:26:12 +02007486int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007487 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007488{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007489 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007490 status,
7491 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007492}
Johan Hedberg2a611692011-02-19 12:06:00 -03007493
Brian Gix604086b2011-11-23 08:28:33 -08007494int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007495 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007496{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007497 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007498 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007499}
7500
Johan Hedberg272d90d2012-02-09 15:26:12 +02007501int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007502 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007503{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007504 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007505 status,
7506 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007507}
7508
Johan Hedberg92a25252012-09-06 18:39:26 +03007509int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7510 u8 link_type, u8 addr_type, u32 passkey,
7511 u8 entered)
7512{
7513 struct mgmt_ev_passkey_notify ev;
7514
7515 BT_DBG("%s", hdev->name);
7516
7517 bacpy(&ev.addr.bdaddr, bdaddr);
7518 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7519 ev.passkey = __cpu_to_le32(passkey);
7520 ev.entered = entered;
7521
7522 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7523}
7524
Johan Hedberge1e930f2014-09-08 17:09:49 -07007525void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007526{
7527 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007528 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007529 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007530
Johan Hedberge1e930f2014-09-08 17:09:49 -07007531 bacpy(&ev.addr.bdaddr, &conn->dst);
7532 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7533 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007534
Johan Hedberge1e930f2014-09-08 17:09:49 -07007535 cmd = find_pairing(conn);
7536
7537 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7538 cmd ? cmd->sk : NULL);
7539
Johan Hedberga511b352014-12-11 21:45:45 +02007540 if (cmd) {
7541 cmd->cmd_complete(cmd, status);
7542 mgmt_pending_remove(cmd);
7543 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007544}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007545
Marcel Holtmann464996a2013-10-15 14:26:24 -07007546void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007547{
7548 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007549 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007550
7551 if (status) {
7552 u8 mgmt_err = mgmt_status(status);
7553 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007554 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007555 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007556 }
7557
Marcel Holtmann464996a2013-10-15 14:26:24 -07007558 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007559 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007560 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007561 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007562
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007563 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007564 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007565
Johan Hedberg47990ea2012-02-22 11:58:37 +02007566 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007567 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007568
7569 if (match.sk)
7570 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007571}
7572
Johan Hedberg890ea892013-03-15 17:06:52 -05007573static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007574{
Johan Hedberg890ea892013-03-15 17:06:52 -05007575 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007576 struct hci_cp_write_eir cp;
7577
Johan Hedberg976eb202012-10-24 21:12:01 +03007578 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007579 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007580
Johan Hedbergc80da272012-02-22 15:38:48 +02007581 memset(hdev->eir, 0, sizeof(hdev->eir));
7582
Johan Hedbergcacaf522012-02-21 00:52:42 +02007583 memset(&cp, 0, sizeof(cp));
7584
Johan Hedberg890ea892013-03-15 17:06:52 -05007585 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007586}
7587
Marcel Holtmann3e248562013-10-15 14:26:25 -07007588void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007589{
7590 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007591 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007592 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007593
7594 if (status) {
7595 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007596
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007597 if (enable && hci_dev_test_and_clear_flag(hdev,
7598 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007599 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007600 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007601 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007602
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007603 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7604 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007605 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007606 }
7607
7608 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007609 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007610 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007611 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007612 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007613 changed = hci_dev_test_and_clear_flag(hdev,
7614 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007615 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007616 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007617 }
7618
7619 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7620
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007621 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007622 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007623
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007624 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007625 sock_put(match.sk);
7626
Johan Hedberg890ea892013-03-15 17:06:52 -05007627 hci_req_init(&req, hdev);
7628
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007629 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7630 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007631 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7632 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007633 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007634 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007635 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007636 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007637
7638 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007639}
7640
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007641static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007642{
7643 struct cmd_lookup *match = data;
7644
Johan Hedberg90e70452012-02-23 23:09:40 +02007645 if (match->sk == NULL) {
7646 match->sk = cmd->sk;
7647 sock_hold(match->sk);
7648 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007649}
7650
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007651void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7652 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007653{
Johan Hedberg90e70452012-02-23 23:09:40 +02007654 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007655
Johan Hedberg92da6092013-03-15 17:06:55 -05007656 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7657 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7658 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007659
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007660 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007661 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7662 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007663 ext_info_changed(hdev, NULL);
7664 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007665
7666 if (match.sk)
7667 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007668}
7669
Marcel Holtmann7667da32013-10-15 14:26:27 -07007670void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007671{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007672 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007673 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007674
Johan Hedberg13928972013-03-15 17:07:00 -05007675 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007676 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007677
7678 memset(&ev, 0, sizeof(ev));
7679 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007680 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007681
Johan Hedberg333ae952015-03-17 13:48:47 +02007682 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007683 if (!cmd) {
7684 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007685
Johan Hedberg13928972013-03-15 17:07:00 -05007686 /* If this is a HCI command related to powering on the
7687 * HCI dev don't send any mgmt signals.
7688 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007689 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007690 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007691 }
7692
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007693 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7694 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007695 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007696}
Szymon Jancc35938b2011-03-22 13:12:21 +01007697
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007698static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7699{
7700 int i;
7701
7702 for (i = 0; i < uuid_count; i++) {
7703 if (!memcmp(uuid, uuids[i], 16))
7704 return true;
7705 }
7706
7707 return false;
7708}
7709
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007710static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7711{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007712 u16 parsed = 0;
7713
7714 while (parsed < eir_len) {
7715 u8 field_len = eir[0];
7716 u8 uuid[16];
7717 int i;
7718
7719 if (field_len == 0)
7720 break;
7721
7722 if (eir_len - parsed < field_len + 1)
7723 break;
7724
7725 switch (eir[1]) {
7726 case EIR_UUID16_ALL:
7727 case EIR_UUID16_SOME:
7728 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007729 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007730 uuid[13] = eir[i + 3];
7731 uuid[12] = eir[i + 2];
7732 if (has_uuid(uuid, uuid_count, uuids))
7733 return true;
7734 }
7735 break;
7736 case EIR_UUID32_ALL:
7737 case EIR_UUID32_SOME:
7738 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007739 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007740 uuid[15] = eir[i + 5];
7741 uuid[14] = eir[i + 4];
7742 uuid[13] = eir[i + 3];
7743 uuid[12] = eir[i + 2];
7744 if (has_uuid(uuid, uuid_count, uuids))
7745 return true;
7746 }
7747 break;
7748 case EIR_UUID128_ALL:
7749 case EIR_UUID128_SOME:
7750 for (i = 0; i + 17 <= field_len; i += 16) {
7751 memcpy(uuid, eir + i + 2, 16);
7752 if (has_uuid(uuid, uuid_count, uuids))
7753 return true;
7754 }
7755 break;
7756 }
7757
7758 parsed += field_len + 1;
7759 eir += field_len + 1;
7760 }
7761
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007762 return false;
7763}
7764
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007765static void restart_le_scan(struct hci_dev *hdev)
7766{
7767 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007768 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007769 return;
7770
7771 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7772 hdev->discovery.scan_start +
7773 hdev->discovery.scan_duration))
7774 return;
7775
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007776 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007777 DISCOV_LE_RESTART_DELAY);
7778}
7779
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007780static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7781 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7782{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007783 /* If a RSSI threshold has been specified, and
7784 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7785 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7786 * is set, let it through for further processing, as we might need to
7787 * restart the scan.
7788 *
7789 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7790 * the results are also dropped.
7791 */
7792 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7793 (rssi == HCI_RSSI_INVALID ||
7794 (rssi < hdev->discovery.rssi &&
7795 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7796 return false;
7797
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007798 if (hdev->discovery.uuid_count != 0) {
7799 /* If a list of UUIDs is provided in filter, results with no
7800 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007801 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007802 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7803 hdev->discovery.uuids) &&
7804 !eir_has_uuids(scan_rsp, scan_rsp_len,
7805 hdev->discovery.uuid_count,
7806 hdev->discovery.uuids))
7807 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007808 }
7809
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007810 /* If duplicate filtering does not report RSSI changes, then restart
7811 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007812 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007813 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7814 restart_le_scan(hdev);
7815
7816 /* Validate RSSI value against the RSSI threshold once more. */
7817 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7818 rssi < hdev->discovery.rssi)
7819 return false;
7820 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007821
7822 return true;
7823}
7824
Marcel Holtmann901801b2013-10-06 23:55:51 -07007825void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007826 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7827 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007828{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007829 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007830 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007831 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007832
Johan Hedberg75ce2082014-07-02 22:42:01 +03007833 /* Don't send events for a non-kernel initiated discovery. With
7834 * LE one exception is if we have pend_le_reports > 0 in which
7835 * case we're doing passive scanning and want these events.
7836 */
7837 if (!hci_discovery_active(hdev)) {
7838 if (link_type == ACL_LINK)
7839 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007840 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007841 return;
7842 }
Andre Guedes12602d02013-04-30 15:29:40 -03007843
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007844 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007845 /* We are using service discovery */
7846 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7847 scan_rsp_len))
7848 return;
7849 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007850
Johan Hedberg78b781c2016-01-05 13:19:32 +02007851 if (hdev->discovery.limited) {
7852 /* Check for limited discoverable bit */
7853 if (dev_class) {
7854 if (!(dev_class[1] & 0x20))
7855 return;
7856 } else {
7857 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7858 if (!flags || !(flags[0] & LE_AD_LIMITED))
7859 return;
7860 }
7861 }
7862
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007863 /* Make sure that the buffer is big enough. The 5 extra bytes
7864 * are for the potential CoD field.
7865 */
7866 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007867 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007868
Johan Hedberg1dc06092012-01-15 21:01:23 +02007869 memset(buf, 0, sizeof(buf));
7870
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007871 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7872 * RSSI value was reported as 0 when not available. This behavior
7873 * is kept when using device discovery. This is required for full
7874 * backwards compatibility with the API.
7875 *
7876 * However when using service discovery, the value 127 will be
7877 * returned when the RSSI is not available.
7878 */
Szymon Janc91200e92015-01-22 16:57:05 +01007879 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7880 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007881 rssi = 0;
7882
Johan Hedberg841c5642014-07-07 12:45:54 +03007883 bacpy(&ev->addr.bdaddr, bdaddr);
7884 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007885 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007886 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007887
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007888 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007889 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007890 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007891
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007892 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7893 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007894 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007895 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007896
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007897 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007898 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007899 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007900
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007901 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7902 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007903
Marcel Holtmann901801b2013-10-06 23:55:51 -07007904 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007905}
Johan Hedberga88a9652011-03-30 13:18:12 +03007906
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007907void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7908 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007909{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007910 struct mgmt_ev_device_found *ev;
7911 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7912 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007913
Johan Hedbergb644ba32012-01-17 21:48:47 +02007914 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007915
Johan Hedbergb644ba32012-01-17 21:48:47 +02007916 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007917
Johan Hedbergb644ba32012-01-17 21:48:47 +02007918 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007919 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007920 ev->rssi = rssi;
7921
7922 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007923 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007924
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007925 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007926
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007927 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007928}
Johan Hedberg314b2382011-04-27 10:29:57 -04007929
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007930void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007931{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007932 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007933
Andre Guedes343fb142011-11-22 17:14:19 -03007934 BT_DBG("%s discovering %u", hdev->name, discovering);
7935
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007936 memset(&ev, 0, sizeof(ev));
7937 ev.type = hdev->discovery.type;
7938 ev.discovering = discovering;
7939
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007940 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007941}
Antti Julku5e762442011-08-25 16:48:02 +03007942
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007943static struct hci_mgmt_chan chan = {
7944 .channel = HCI_CHANNEL_CONTROL,
7945 .handler_count = ARRAY_SIZE(mgmt_handlers),
7946 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007947 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007948};
7949
7950int mgmt_init(void)
7951{
7952 return hci_mgmt_chan_register(&chan);
7953}
7954
7955void mgmt_exit(void)
7956{
7957 hci_mgmt_chan_unregister(&chan);
7958}