blob: ccce954f814682a40ba5d8af0ab463d5b0bfda3b [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 Holtmannedd38962014-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;
477 size_t rp_len;
478 u16 count;
479 int err;
480
481 BT_DBG("sock %p", sk);
482
483 read_lock(&hci_dev_list_lock);
484
485 count = 0;
486 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200487 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700488 count++;
489 }
490
491 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
492 rp = kmalloc(rp_len, GFP_ATOMIC);
493 if (!rp) {
494 read_unlock(&hci_dev_list_lock);
495 return -ENOMEM;
496 }
497
498 count = 0;
499 list_for_each_entry(d, &hci_dev_list, list) {
500 if (hci_dev_test_flag(d, HCI_SETUP) ||
501 hci_dev_test_flag(d, HCI_CONFIG) ||
502 hci_dev_test_flag(d, HCI_USER_CHANNEL))
503 continue;
504
505 /* Devices marked as raw-only are neither configured
506 * nor unconfigured controllers.
507 */
508 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
509 continue;
510
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200511 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700512 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
513 rp->entry[count].type = 0x01;
514 else
515 rp->entry[count].type = 0x00;
516 } else if (d->dev_type == HCI_AMP) {
517 rp->entry[count].type = 0x02;
518 } else {
519 continue;
520 }
521
522 rp->entry[count].bus = d->bus;
523 rp->entry[count++].index = cpu_to_le16(d->id);
524 BT_DBG("Added hci%u", d->id);
525 }
526
527 rp->num_controllers = cpu_to_le16(count);
528 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
529
530 read_unlock(&hci_dev_list_lock);
531
532 /* If this command is called at least once, then all the
533 * default index and unconfigured index events are disabled
534 * and from now on only extended index events are used.
535 */
536 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
537 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
538 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
539
540 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
541 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
542
543 kfree(rp);
544
545 return err;
546}
547
Marcel Holtmanndbece372014-07-04 18:11:55 +0200548static bool is_configured(struct hci_dev *hdev)
549{
550 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700551 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200552 return false;
553
554 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
555 !bacmp(&hdev->public_addr, BDADDR_ANY))
556 return false;
557
558 return true;
559}
560
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200561static __le32 get_missing_options(struct hci_dev *hdev)
562{
563 u32 options = 0;
564
Marcel Holtmanndbece372014-07-04 18:11:55 +0200565 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700566 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200567 options |= MGMT_OPTION_EXTERNAL_CONFIG;
568
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200569 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
570 !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 Holtmann08dc0e92015-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
Johan Hedberg86742e12011-11-07 23:13:38 +02002304 expected_len = sizeof(*cp) + key_count *
2305 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002306 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002307 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2308 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002309 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2310 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002311 }
2312
Johan Hedberg4ae14302013-01-20 14:27:13 +02002313 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2315 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002316
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002317 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002318 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002319
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002320 for (i = 0; i < key_count; i++) {
2321 struct mgmt_link_key_info *key = &cp->keys[i];
2322
Marcel Holtmann8e991132014-01-10 02:07:25 -08002323 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002324 return mgmt_cmd_status(sk, hdev->id,
2325 MGMT_OP_LOAD_LINK_KEYS,
2326 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002327 }
2328
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002329 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002330
2331 hci_link_keys_clear(hdev);
2332
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002334 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002335 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002336 changed = hci_dev_test_and_clear_flag(hdev,
2337 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002338
2339 if (changed)
2340 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002342 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002343 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344
Johan Hedberg58e92932014-06-24 14:00:26 +03002345 /* Always ignore debug keys and require a new pairing if
2346 * the user wants to use them.
2347 */
2348 if (key->type == HCI_LK_DEBUG_COMBINATION)
2349 continue;
2350
Johan Hedberg7652ff62014-06-24 13:15:49 +03002351 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2352 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353 }
2354
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002355 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002357 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002359 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360}
2361
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002362static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002364{
2365 struct mgmt_ev_device_unpaired ev;
2366
2367 bacpy(&ev.addr.bdaddr, bdaddr);
2368 ev.addr.type = addr_type;
2369
2370 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002372}
2373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002377 struct mgmt_cp_unpair_device *cp = data;
2378 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002379 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002380 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002381 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002382 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002383 int err;
2384
Johan Hedberga8a1d192011-11-10 15:54:38 +02002385 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002386 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2387 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002388
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002389 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002390 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2391 MGMT_STATUS_INVALID_PARAMS,
2392 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002393
Johan Hedberg118da702013-01-20 14:27:20 +02002394 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002395 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2396 MGMT_STATUS_INVALID_PARAMS,
2397 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002398
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399 hci_dev_lock(hdev);
2400
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002401 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002402 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2403 MGMT_STATUS_NOT_POWERED, &rp,
2404 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002405 goto unlock;
2406 }
2407
Johan Hedberge0b2b272014-02-18 17:14:31 +02002408 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002409 /* If disconnection is requested, then look up the
2410 * connection. If the remote device is connected, it
2411 * will be later used to terminate the link.
2412 *
2413 * Setting it to NULL explicitly will cause no
2414 * termination of the link.
2415 */
2416 if (cp->disconnect)
2417 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2418 &cp->addr.bdaddr);
2419 else
2420 conn = NULL;
2421
Johan Hedberg124f6e32012-02-09 13:50:12 +02002422 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002423 if (err < 0) {
2424 err = mgmt_cmd_complete(sk, hdev->id,
2425 MGMT_OP_UNPAIR_DEVICE,
2426 MGMT_STATUS_NOT_PAIRED, &rp,
2427 sizeof(rp));
2428 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002429 }
2430
Johan Hedbergec182f02015-10-21 18:03:03 +03002431 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002432 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002433
Johan Hedbergec182f02015-10-21 18:03:03 +03002434 /* LE address type */
2435 addr_type = le_addr_type(cp->addr.type);
2436
Matias Karhumaacb28c302018-09-26 09:13:46 +03002437 /* Abort any ongoing SMP pairing. Removes ltk and irk if they exist. */
2438 err = smp_cancel_and_remove_pairing(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002439 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002440 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2441 MGMT_STATUS_NOT_PAIRED, &rp,
2442 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002443 goto unlock;
2444 }
2445
Johan Hedbergec182f02015-10-21 18:03:03 +03002446 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2447 if (!conn) {
2448 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2449 goto done;
2450 }
2451
Johan Hedbergc81d5552015-10-22 09:38:35 +03002452
Johan Hedbergec182f02015-10-21 18:03:03 +03002453 /* Defer clearing up the connection parameters until closing to
2454 * give a chance of keeping them if a repairing happens.
2455 */
2456 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2457
Johan Hedbergfc643612015-10-22 09:38:31 +03002458 /* Disable auto-connection parameters if present */
2459 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2460 if (params) {
2461 if (params->explicit_connect)
2462 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2463 else
2464 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2465 }
2466
Johan Hedbergec182f02015-10-21 18:03:03 +03002467 /* If disconnection is not requested, then clear the connection
2468 * variable so that the link is not terminated.
2469 */
2470 if (!cp->disconnect)
2471 conn = NULL;
2472
2473done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002474 /* If the connection variable is set, then termination of the
2475 * link is requested.
2476 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002477 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002478 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2479 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002480 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002481 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002482 }
2483
Johan Hedberg124f6e32012-02-09 13:50:12 +02002484 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002485 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002486 if (!cmd) {
2487 err = -ENOMEM;
2488 goto unlock;
2489 }
2490
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002491 cmd->cmd_complete = addr_cmd_complete;
2492
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002493 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002494 if (err < 0)
2495 mgmt_pending_remove(cmd);
2496
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002497unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002498 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002499 return err;
2500}
2501
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002502static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002503 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002504{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002505 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002506 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002507 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002508 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002509 int err;
2510
2511 BT_DBG("");
2512
Johan Hedberg06a63b12013-01-20 14:27:21 +02002513 memset(&rp, 0, sizeof(rp));
2514 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2515 rp.addr.type = cp->addr.type;
2516
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002517 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002518 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2519 MGMT_STATUS_INVALID_PARAMS,
2520 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002521
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002522 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002523
2524 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002525 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2526 MGMT_STATUS_NOT_POWERED, &rp,
2527 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002528 goto failed;
2529 }
2530
Johan Hedberg333ae952015-03-17 13:48:47 +02002531 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002532 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2533 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002534 goto failed;
2535 }
2536
Andre Guedes591f47f2012-04-24 21:02:49 -03002537 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002538 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2539 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002540 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002541 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2542 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002543
Vishal Agarwalf9607272012-06-13 05:32:43 +05302544 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002545 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2546 MGMT_STATUS_NOT_CONNECTED, &rp,
2547 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002548 goto failed;
2549 }
2550
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002551 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002552 if (!cmd) {
2553 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002554 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002555 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002556
Johan Hedbergf5818c22014-12-05 13:36:02 +02002557 cmd->cmd_complete = generic_cmd_complete;
2558
Johan Hedberge3f2f922014-08-18 20:33:33 +03002559 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002560 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002561 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002562
2563failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002564 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565 return err;
2566}
2567
Andre Guedes57c14772012-04-24 21:02:50 -03002568static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002569{
2570 switch (link_type) {
2571 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002572 switch (addr_type) {
2573 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002574 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002575
Johan Hedberg48264f02011-11-09 13:58:58 +02002576 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002577 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002578 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002579 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002580
Johan Hedberg4c659c32011-11-07 23:13:39 +02002581 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002582 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002583 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002584 }
2585}
2586
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002587static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2588 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002589{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002590 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002591 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002592 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002593 int err;
2594 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002595
2596 BT_DBG("");
2597
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002598 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002599
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002600 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002601 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2602 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002603 goto unlock;
2604 }
2605
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002606 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002607 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2608 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002609 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002610 }
2611
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002612 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002613 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002614 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002615 err = -ENOMEM;
2616 goto unlock;
2617 }
2618
Johan Hedberg2784eb42011-01-21 13:56:35 +02002619 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002620 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002621 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2622 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002623 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002624 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002625 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002626 continue;
2627 i++;
2628 }
2629
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002630 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002631
Johan Hedberg4c659c32011-11-07 23:13:39 +02002632 /* Recalculate length in case of filtered SCO connections, etc */
2633 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002634
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002635 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2636 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002637
Johan Hedberga38528f2011-01-22 06:46:43 +02002638 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002639
2640unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002641 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002642 return err;
2643}
2644
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002645static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002646 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002647{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002648 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002649 int err;
2650
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002651 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002652 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002653 if (!cmd)
2654 return -ENOMEM;
2655
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002656 cmd->cmd_complete = addr_cmd_complete;
2657
Johan Hedbergd8457692012-02-17 14:24:57 +02002658 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002659 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002660 if (err < 0)
2661 mgmt_pending_remove(cmd);
2662
2663 return err;
2664}
2665
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002666static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002667 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002668{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002669 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002670 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002671 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002672 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002673 int err;
2674
2675 BT_DBG("");
2676
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002677 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002678
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002679 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002680 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2681 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002682 goto failed;
2683 }
2684
Johan Hedbergd8457692012-02-17 14:24:57 +02002685 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002686 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002687 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2688 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002689 goto failed;
2690 }
2691
2692 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002693 struct mgmt_cp_pin_code_neg_reply ncp;
2694
2695 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002696
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002697 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002699 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002700 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002701 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2702 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002703
2704 goto failed;
2705 }
2706
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002707 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002708 if (!cmd) {
2709 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002710 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002711 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002712
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002713 cmd->cmd_complete = addr_cmd_complete;
2714
Johan Hedbergd8457692012-02-17 14:24:57 +02002715 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002716 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002717 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718
2719 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2720 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002721 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002722
2723failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002724 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725 return err;
2726}
2727
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002728static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2729 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002730{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002731 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002732
2733 BT_DBG("");
2734
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002735 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002736 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2737 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002739 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002740
2741 hdev->io_capability = cp->io_capability;
2742
2743 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002744 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002745
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002746 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002747
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002748 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2749 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002750}
2751
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002752static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002753{
2754 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002755 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002756
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002757 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002758 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2759 continue;
2760
Johan Hedberge9a416b2011-02-19 12:05:56 -03002761 if (cmd->user_data != conn)
2762 continue;
2763
2764 return cmd;
2765 }
2766
2767 return NULL;
2768}
2769
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002770static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002771{
2772 struct mgmt_rp_pair_device rp;
2773 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002774 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002775
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002776 bacpy(&rp.addr.bdaddr, &conn->dst);
2777 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002778
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002779 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2780 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002781
2782 /* So we don't get further callbacks for this connection */
2783 conn->connect_cfm_cb = NULL;
2784 conn->security_cfm_cb = NULL;
2785 conn->disconn_cfm_cb = NULL;
2786
David Herrmann76a68ba2013-04-06 20:28:37 +02002787 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002788
2789 /* The device is paired so there is no need to remove
2790 * its connection parameters anymore.
2791 */
2792 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002793
2794 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002795
2796 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002797}
2798
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002799void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2800{
2801 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002802 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002803
2804 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002805 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002806 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002807 mgmt_pending_remove(cmd);
2808 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002809}
2810
Johan Hedberge9a416b2011-02-19 12:05:56 -03002811static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2812{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002813 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002814
2815 BT_DBG("status %u", status);
2816
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002817 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002818 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002819 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002820 return;
2821 }
2822
2823 cmd->cmd_complete(cmd, mgmt_status(status));
2824 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002825}
2826
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002827static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302828{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002829 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302830
2831 BT_DBG("status %u", status);
2832
2833 if (!status)
2834 return;
2835
2836 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002837 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302838 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002839 return;
2840 }
2841
2842 cmd->cmd_complete(cmd, mgmt_status(status));
2843 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302844}
2845
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002846static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002847 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002848{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002849 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002850 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002851 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002852 u8 sec_level, auth_type;
2853 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002854 int err;
2855
2856 BT_DBG("");
2857
Szymon Jancf950a30e2013-01-18 12:48:07 +01002858 memset(&rp, 0, sizeof(rp));
2859 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2860 rp.addr.type = cp->addr.type;
2861
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002862 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002863 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2864 MGMT_STATUS_INVALID_PARAMS,
2865 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002866
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002867 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002868 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2869 MGMT_STATUS_INVALID_PARAMS,
2870 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002871
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002872 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002873
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002874 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002875 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2876 MGMT_STATUS_NOT_POWERED, &rp,
2877 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002878 goto unlock;
2879 }
2880
Johan Hedberg55e76b32015-03-10 22:34:40 +02002881 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2882 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2883 MGMT_STATUS_ALREADY_PAIRED, &rp,
2884 sizeof(rp));
2885 goto unlock;
2886 }
2887
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002888 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002889 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002890
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002891 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002892 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2893 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002894 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002895 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002896 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002897
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002898 /* When pairing a new device, it is expected to remember
2899 * this device for future connections. Adding the connection
2900 * parameter information ahead of time allows tracking
2901 * of the slave preferred values and will speed up any
2902 * further connection establishment.
2903 *
2904 * If connection parameters already exist, then they
2905 * will be kept and this function does nothing.
2906 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002907 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2908
2909 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2910 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002911
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002912 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2913 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002914 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002915 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002916
Ville Tervo30e76272011-02-22 16:10:53 -03002917 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002918 int status;
2919
2920 if (PTR_ERR(conn) == -EBUSY)
2921 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002922 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2923 status = MGMT_STATUS_NOT_SUPPORTED;
2924 else if (PTR_ERR(conn) == -ECONNREFUSED)
2925 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002926 else
2927 status = MGMT_STATUS_CONNECT_FAILED;
2928
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002929 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2930 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002931 goto unlock;
2932 }
2933
2934 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002935 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002936 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2937 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002938 goto unlock;
2939 }
2940
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002941 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002942 if (!cmd) {
2943 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002944 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002945 goto unlock;
2946 }
2947
Johan Hedberg04ab2742014-12-05 13:36:04 +02002948 cmd->cmd_complete = pairing_complete;
2949
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002950 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002951 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002952 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002953 conn->security_cfm_cb = pairing_complete_cb;
2954 conn->disconn_cfm_cb = pairing_complete_cb;
2955 } else {
2956 conn->connect_cfm_cb = le_pairing_complete_cb;
2957 conn->security_cfm_cb = le_pairing_complete_cb;
2958 conn->disconn_cfm_cb = le_pairing_complete_cb;
2959 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002960
Johan Hedberge9a416b2011-02-19 12:05:56 -03002961 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002962 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002963
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002964 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002965 hci_conn_security(conn, sec_level, auth_type, true)) {
2966 cmd->cmd_complete(cmd, 0);
2967 mgmt_pending_remove(cmd);
2968 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002969
2970 err = 0;
2971
2972unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002973 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002974 return err;
2975}
2976
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002977static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2978 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002979{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002980 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002981 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002982 struct hci_conn *conn;
2983 int err;
2984
2985 BT_DBG("");
2986
Johan Hedberg28424702012-02-02 04:02:29 +02002987 hci_dev_lock(hdev);
2988
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002989 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002990 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2991 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002992 goto unlock;
2993 }
2994
Johan Hedberg333ae952015-03-17 13:48:47 +02002995 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002996 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002997 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2998 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002999 goto unlock;
3000 }
3001
3002 conn = cmd->user_data;
3003
3004 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003005 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3006 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003007 goto unlock;
3008 }
3009
Johan Hedberga511b352014-12-11 21:45:45 +02003010 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3011 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003012
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003013 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3014 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003015unlock:
3016 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003017 return err;
3018}
3019
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003020static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003021 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003022 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003023{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003024 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003025 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003026 int err;
3027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003028 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003029
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003030 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003031 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3032 MGMT_STATUS_NOT_POWERED, addr,
3033 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003034 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003035 }
3036
Johan Hedberg1707c602013-03-15 17:07:15 -05003037 if (addr->type == BDADDR_BREDR)
3038 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003039 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003040 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3041 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003042
Johan Hedberg272d90d2012-02-09 15:26:12 +02003043 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003044 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3045 MGMT_STATUS_NOT_CONNECTED, addr,
3046 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003047 goto done;
3048 }
3049
Johan Hedberg1707c602013-03-15 17:07:15 -05003050 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003051 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003052 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003053 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3054 MGMT_STATUS_SUCCESS, addr,
3055 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003056 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003057 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3058 MGMT_STATUS_FAILED, addr,
3059 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003060
Brian Gix47c15e22011-11-16 13:53:14 -08003061 goto done;
3062 }
3063
Johan Hedberg1707c602013-03-15 17:07:15 -05003064 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003065 if (!cmd) {
3066 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003067 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003068 }
3069
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003070 cmd->cmd_complete = addr_cmd_complete;
3071
Brian Gix0df4c182011-11-16 13:53:13 -08003072 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003073 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3074 struct hci_cp_user_passkey_reply cp;
3075
Johan Hedberg1707c602013-03-15 17:07:15 -05003076 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003077 cp.passkey = passkey;
3078 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3079 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003080 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3081 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003082
Johan Hedberga664b5b2011-02-19 12:06:02 -03003083 if (err < 0)
3084 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003085
Brian Gix0df4c182011-11-16 13:53:13 -08003086done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003087 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003088 return err;
3089}
3090
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303091static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3092 void *data, u16 len)
3093{
3094 struct mgmt_cp_pin_code_neg_reply *cp = data;
3095
3096 BT_DBG("");
3097
Johan Hedberg1707c602013-03-15 17:07:15 -05003098 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303099 MGMT_OP_PIN_CODE_NEG_REPLY,
3100 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3101}
3102
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003103static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3104 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003105{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003106 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003107
3108 BT_DBG("");
3109
3110 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003111 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3112 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003113
Johan Hedberg1707c602013-03-15 17:07:15 -05003114 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003115 MGMT_OP_USER_CONFIRM_REPLY,
3116 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003117}
3118
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003119static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003120 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003121{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003122 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003123
3124 BT_DBG("");
3125
Johan Hedberg1707c602013-03-15 17:07:15 -05003126 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3128 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003129}
3130
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3132 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003133{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003134 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003135
3136 BT_DBG("");
3137
Johan Hedberg1707c602013-03-15 17:07:15 -05003138 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003139 MGMT_OP_USER_PASSKEY_REPLY,
3140 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003141}
3142
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003143static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003145{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003146 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003147
3148 BT_DBG("");
3149
Johan Hedberg1707c602013-03-15 17:07:15 -05003150 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003151 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3152 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003153}
3154
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003155static void adv_expire(struct hci_dev *hdev, u32 flags)
3156{
3157 struct adv_info *adv_instance;
3158 struct hci_request req;
3159 int err;
3160
3161 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3162 if (!adv_instance)
3163 return;
3164
3165 /* stop if current instance doesn't need to be changed */
3166 if (!(adv_instance->flags & flags))
3167 return;
3168
3169 cancel_adv_timeout(hdev);
3170
3171 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3172 if (!adv_instance)
3173 return;
3174
3175 hci_req_init(&req, hdev);
3176 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3177 true);
3178 if (err)
3179 return;
3180
3181 hci_req_run(&req, NULL);
3182}
3183
Marcel Holtmann1904a852015-01-11 13:50:44 -08003184static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003185{
3186 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003187 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003188
3189 BT_DBG("status 0x%02x", status);
3190
3191 hci_dev_lock(hdev);
3192
Johan Hedberg333ae952015-03-17 13:48:47 +02003193 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003194 if (!cmd)
3195 goto unlock;
3196
3197 cp = cmd->param;
3198
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003199 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003200 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3201 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003202 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003203 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3204 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003205
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003206 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3207 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3208 }
3209
Johan Hedberg13928972013-03-15 17:07:00 -05003210 mgmt_pending_remove(cmd);
3211
3212unlock:
3213 hci_dev_unlock(hdev);
3214}
3215
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003216static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003217 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003218{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003219 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003220 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003221 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003222 int err;
3223
3224 BT_DBG("");
3225
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003226 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003227
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003228 /* If the old values are the same as the new ones just return a
3229 * direct command complete event.
3230 */
3231 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3232 !memcmp(hdev->short_name, cp->short_name,
3233 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003234 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3235 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003236 goto failed;
3237 }
3238
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003239 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003240
Johan Hedbergb5235a62012-02-21 14:32:24 +02003241 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003242 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003243
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003244 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3245 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003246 if (err < 0)
3247 goto failed;
3248
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003249 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3250 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003251 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003252
Johan Hedbergb5235a62012-02-21 14:32:24 +02003253 goto failed;
3254 }
3255
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003256 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003257 if (!cmd) {
3258 err = -ENOMEM;
3259 goto failed;
3260 }
3261
Johan Hedberg13928972013-03-15 17:07:00 -05003262 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3263
Johan Hedberg890ea892013-03-15 17:06:52 -05003264 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003265
3266 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003267 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003268 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003269 }
3270
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003271 /* The name is stored in the scan response data and so
3272 * no need to udpate the advertising data here.
3273 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003274 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003275 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003276
Johan Hedberg13928972013-03-15 17:07:00 -05003277 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003278 if (err < 0)
3279 mgmt_pending_remove(cmd);
3280
3281failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003282 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003283 return err;
3284}
3285
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003286static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3287 u16 len)
3288{
3289 struct mgmt_cp_set_appearance *cp = data;
3290 u16 apperance;
3291 int err;
3292
3293 BT_DBG("");
3294
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003295 if (!lmp_le_capable(hdev))
3296 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3297 MGMT_STATUS_NOT_SUPPORTED);
3298
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003299 apperance = le16_to_cpu(cp->appearance);
3300
3301 hci_dev_lock(hdev);
3302
3303 if (hdev->appearance != apperance) {
3304 hdev->appearance = apperance;
3305
3306 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3307 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003308
3309 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003310 }
3311
3312 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3313 0);
3314
3315 hci_dev_unlock(hdev);
3316
3317 return err;
3318}
3319
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303320static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3321 void *data, u16 len)
3322{
3323 struct mgmt_rp_get_phy_confguration rp;
3324
3325 BT_DBG("sock %p %s", sk, hdev->name);
3326
3327 hci_dev_lock(hdev);
3328
3329 memset(&rp, 0, sizeof(rp));
3330
3331 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3332 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3333 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3334
3335 hci_dev_unlock(hdev);
3336
3337 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3338 &rp, sizeof(rp));
3339}
3340
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303341int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3342{
3343 struct mgmt_ev_phy_configuration_changed ev;
3344
3345 memset(&ev, 0, sizeof(ev));
3346
3347 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3348
3349 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3350 sizeof(ev), skip);
3351}
3352
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303353static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3354 u16 opcode, struct sk_buff *skb)
3355{
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303356 struct mgmt_pending_cmd *cmd;
3357
3358 BT_DBG("status 0x%02x", status);
3359
3360 hci_dev_lock(hdev);
3361
3362 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3363 if (!cmd)
3364 goto unlock;
3365
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303366 if (status) {
3367 mgmt_cmd_status(cmd->sk, hdev->id,
3368 MGMT_OP_SET_PHY_CONFIGURATION,
3369 mgmt_status(status));
3370 } else {
3371 mgmt_cmd_complete(cmd->sk, hdev->id,
3372 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3373 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303374
3375 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303376 }
3377
3378 mgmt_pending_remove(cmd);
3379
3380unlock:
3381 hci_dev_unlock(hdev);
3382}
3383
3384static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3385 void *data, u16 len)
3386{
3387 struct mgmt_cp_set_phy_confguration *cp = data;
3388 struct hci_cp_le_set_default_phy cp_phy;
3389 struct mgmt_pending_cmd *cmd;
3390 struct hci_request req;
3391 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3392 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303393 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303394 int err;
3395
3396 BT_DBG("sock %p %s", sk, hdev->name);
3397
3398 configurable_phys = get_configurable_phys(hdev);
3399 supported_phys = get_supported_phys(hdev);
3400 selected_phys = __le32_to_cpu(cp->selected_phys);
3401
3402 if (selected_phys & ~supported_phys)
3403 return mgmt_cmd_status(sk, hdev->id,
3404 MGMT_OP_SET_PHY_CONFIGURATION,
3405 MGMT_STATUS_INVALID_PARAMS);
3406
3407 unconfigure_phys = supported_phys & ~configurable_phys;
3408
3409 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3410 return mgmt_cmd_status(sk, hdev->id,
3411 MGMT_OP_SET_PHY_CONFIGURATION,
3412 MGMT_STATUS_INVALID_PARAMS);
3413
3414 if (selected_phys == get_selected_phys(hdev))
3415 return mgmt_cmd_complete(sk, hdev->id,
3416 MGMT_OP_SET_PHY_CONFIGURATION,
3417 0, NULL, 0);
3418
3419 hci_dev_lock(hdev);
3420
3421 if (!hdev_is_powered(hdev)) {
3422 err = mgmt_cmd_status(sk, hdev->id,
3423 MGMT_OP_SET_PHY_CONFIGURATION,
3424 MGMT_STATUS_REJECTED);
3425 goto unlock;
3426 }
3427
3428 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3429 err = mgmt_cmd_status(sk, hdev->id,
3430 MGMT_OP_SET_PHY_CONFIGURATION,
3431 MGMT_STATUS_BUSY);
3432 goto unlock;
3433 }
3434
3435 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3436 pkt_type |= (HCI_DH3 | HCI_DM3);
3437 else
3438 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3439
3440 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3441 pkt_type |= (HCI_DH5 | HCI_DM5);
3442 else
3443 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3444
3445 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3446 pkt_type &= ~HCI_2DH1;
3447 else
3448 pkt_type |= HCI_2DH1;
3449
3450 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3451 pkt_type &= ~HCI_2DH3;
3452 else
3453 pkt_type |= HCI_2DH3;
3454
3455 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3456 pkt_type &= ~HCI_2DH5;
3457 else
3458 pkt_type |= HCI_2DH5;
3459
3460 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3461 pkt_type &= ~HCI_3DH1;
3462 else
3463 pkt_type |= HCI_3DH1;
3464
3465 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3466 pkt_type &= ~HCI_3DH3;
3467 else
3468 pkt_type |= HCI_3DH3;
3469
3470 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3471 pkt_type &= ~HCI_3DH5;
3472 else
3473 pkt_type |= HCI_3DH5;
3474
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303475 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303476 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303477 changed = true;
3478 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303479
3480 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3481 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303482 if (changed)
3483 mgmt_phy_configuration_changed(hdev, sk);
3484
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303485 err = mgmt_cmd_complete(sk, hdev->id,
3486 MGMT_OP_SET_PHY_CONFIGURATION,
3487 0, NULL, 0);
3488
3489 goto unlock;
3490 }
3491
3492 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3493 len);
3494 if (!cmd) {
3495 err = -ENOMEM;
3496 goto unlock;
3497 }
3498
3499 hci_req_init(&req, hdev);
3500
3501 memset(&cp_phy, 0, sizeof(cp_phy));
3502
3503 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3504 cp_phy.all_phys |= 0x01;
3505
3506 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3507 cp_phy.all_phys |= 0x02;
3508
3509 if (selected_phys & MGMT_PHY_LE_1M_TX)
3510 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3511
3512 if (selected_phys & MGMT_PHY_LE_2M_TX)
3513 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3514
3515 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3516 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3517
3518 if (selected_phys & MGMT_PHY_LE_1M_RX)
3519 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3520
3521 if (selected_phys & MGMT_PHY_LE_2M_RX)
3522 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3523
3524 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3525 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3526
3527 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3528
3529 err = hci_req_run_skb(&req, set_default_phy_complete);
3530 if (err < 0)
3531 mgmt_pending_remove(cmd);
3532
3533unlock:
3534 hci_dev_unlock(hdev);
3535
3536 return err;
3537}
3538
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003539static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3540 u16 opcode, struct sk_buff *skb)
3541{
3542 struct mgmt_rp_read_local_oob_data mgmt_rp;
3543 size_t rp_size = sizeof(mgmt_rp);
3544 struct mgmt_pending_cmd *cmd;
3545
3546 BT_DBG("%s status %u", hdev->name, status);
3547
3548 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3549 if (!cmd)
3550 return;
3551
3552 if (status || !skb) {
3553 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3554 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3555 goto remove;
3556 }
3557
3558 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3559
3560 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3561 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3562
3563 if (skb->len < sizeof(*rp)) {
3564 mgmt_cmd_status(cmd->sk, hdev->id,
3565 MGMT_OP_READ_LOCAL_OOB_DATA,
3566 MGMT_STATUS_FAILED);
3567 goto remove;
3568 }
3569
3570 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3571 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3572
3573 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3574 } else {
3575 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3576
3577 if (skb->len < sizeof(*rp)) {
3578 mgmt_cmd_status(cmd->sk, hdev->id,
3579 MGMT_OP_READ_LOCAL_OOB_DATA,
3580 MGMT_STATUS_FAILED);
3581 goto remove;
3582 }
3583
3584 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3585 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3586
3587 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3588 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3589 }
3590
3591 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3592 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3593
3594remove:
3595 mgmt_pending_remove(cmd);
3596}
3597
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003598static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003599 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003600{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003601 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003602 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003603 int err;
3604
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003605 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003606
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003607 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003608
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003609 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003610 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3611 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003612 goto unlock;
3613 }
3614
Andre Guedes9a1a1992012-07-24 15:03:48 -03003615 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003616 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3617 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003618 goto unlock;
3619 }
3620
Johan Hedberg333ae952015-03-17 13:48:47 +02003621 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003622 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3623 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003624 goto unlock;
3625 }
3626
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003627 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003628 if (!cmd) {
3629 err = -ENOMEM;
3630 goto unlock;
3631 }
3632
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003633 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003634
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003635 if (bredr_sc_enabled(hdev))
3636 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3637 else
3638 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3639
3640 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003641 if (err < 0)
3642 mgmt_pending_remove(cmd);
3643
3644unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003645 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003646 return err;
3647}
3648
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003649static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003650 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003651{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003652 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003653 int err;
3654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003655 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003656
Johan Hedberg5d57e792015-01-23 10:10:38 +02003657 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003658 return mgmt_cmd_complete(sk, hdev->id,
3659 MGMT_OP_ADD_REMOTE_OOB_DATA,
3660 MGMT_STATUS_INVALID_PARAMS,
3661 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003662
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003663 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003664
Marcel Holtmannec109112014-01-10 02:07:30 -08003665 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3666 struct mgmt_cp_add_remote_oob_data *cp = data;
3667 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003668
Johan Hedbergc19a4952014-11-17 20:52:19 +02003669 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003670 err = mgmt_cmd_complete(sk, hdev->id,
3671 MGMT_OP_ADD_REMOTE_OOB_DATA,
3672 MGMT_STATUS_INVALID_PARAMS,
3673 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003674 goto unlock;
3675 }
3676
Marcel Holtmannec109112014-01-10 02:07:30 -08003677 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003678 cp->addr.type, cp->hash,
3679 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003680 if (err < 0)
3681 status = MGMT_STATUS_FAILED;
3682 else
3683 status = MGMT_STATUS_SUCCESS;
3684
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003685 err = mgmt_cmd_complete(sk, hdev->id,
3686 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3687 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003688 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3689 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003690 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003691 u8 status;
3692
Johan Hedberg86df9202014-10-26 20:52:27 +01003693 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003694 /* Enforce zero-valued 192-bit parameters as
3695 * long as legacy SMP OOB isn't implemented.
3696 */
3697 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3698 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003699 err = mgmt_cmd_complete(sk, hdev->id,
3700 MGMT_OP_ADD_REMOTE_OOB_DATA,
3701 MGMT_STATUS_INVALID_PARAMS,
3702 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003703 goto unlock;
3704 }
3705
Johan Hedberg86df9202014-10-26 20:52:27 +01003706 rand192 = NULL;
3707 hash192 = NULL;
3708 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003709 /* In case one of the P-192 values is set to zero,
3710 * then just disable OOB data for P-192.
3711 */
3712 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3713 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3714 rand192 = NULL;
3715 hash192 = NULL;
3716 } else {
3717 rand192 = cp->rand192;
3718 hash192 = cp->hash192;
3719 }
3720 }
3721
3722 /* In case one of the P-256 values is set to zero, then just
3723 * disable OOB data for P-256.
3724 */
3725 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3726 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3727 rand256 = NULL;
3728 hash256 = NULL;
3729 } else {
3730 rand256 = cp->rand256;
3731 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003732 }
3733
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003734 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003735 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003736 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003737 if (err < 0)
3738 status = MGMT_STATUS_FAILED;
3739 else
3740 status = MGMT_STATUS_SUCCESS;
3741
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003742 err = mgmt_cmd_complete(sk, hdev->id,
3743 MGMT_OP_ADD_REMOTE_OOB_DATA,
3744 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003745 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003746 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
3747 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003748 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3749 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003750 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003751
Johan Hedbergc19a4952014-11-17 20:52:19 +02003752unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003753 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003754 return err;
3755}
3756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003757static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003758 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003759{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003760 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003761 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003762 int err;
3763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003764 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003765
Johan Hedbergc19a4952014-11-17 20:52:19 +02003766 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003767 return mgmt_cmd_complete(sk, hdev->id,
3768 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3769 MGMT_STATUS_INVALID_PARAMS,
3770 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003772 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003773
Johan Hedbergeedbd582014-11-15 09:34:23 +02003774 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3775 hci_remote_oob_data_clear(hdev);
3776 status = MGMT_STATUS_SUCCESS;
3777 goto done;
3778 }
3779
Johan Hedberg6928a922014-10-26 20:46:09 +01003780 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003781 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003782 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003783 else
Szymon Janca6785be2012-12-13 15:11:21 +01003784 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003785
Johan Hedbergeedbd582014-11-15 09:34:23 +02003786done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003787 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3788 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003789
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003790 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003791 return err;
3792}
3793
Johan Hedberge68f0722015-11-11 08:30:30 +02003794void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003795{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003796 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003797
Andre Guedes7c307722013-04-30 15:29:28 -03003798 BT_DBG("status %d", status);
3799
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003800 hci_dev_lock(hdev);
3801
Johan Hedberg333ae952015-03-17 13:48:47 +02003802 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003803 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003804 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003805
Johan Hedberg78b781c2016-01-05 13:19:32 +02003806 if (!cmd)
3807 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3808
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003809 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003810 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003811 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003812 }
3813
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003814 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003815}
3816
Johan Hedberg591752a2015-11-11 08:11:24 +02003817static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3818 uint8_t *mgmt_status)
3819{
3820 switch (type) {
3821 case DISCOV_TYPE_LE:
3822 *mgmt_status = mgmt_le_support(hdev);
3823 if (*mgmt_status)
3824 return false;
3825 break;
3826 case DISCOV_TYPE_INTERLEAVED:
3827 *mgmt_status = mgmt_le_support(hdev);
3828 if (*mgmt_status)
3829 return false;
3830 /* Intentional fall-through */
3831 case DISCOV_TYPE_BREDR:
3832 *mgmt_status = mgmt_bredr_support(hdev);
3833 if (*mgmt_status)
3834 return false;
3835 break;
3836 default:
3837 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3838 return false;
3839 }
3840
3841 return true;
3842}
3843
Johan Hedberg78b781c2016-01-05 13:19:32 +02003844static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3845 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003846{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003847 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003848 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003849 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003850 int err;
3851
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003852 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003853
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003854 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003855
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003856 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003857 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003858 MGMT_STATUS_NOT_POWERED,
3859 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003860 goto failed;
3861 }
3862
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003863 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003864 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003865 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3866 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003867 goto failed;
3868 }
3869
Johan Hedberg591752a2015-11-11 08:11:24 +02003870 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003871 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3872 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003873 goto failed;
3874 }
3875
Marcel Holtmann22078802014-12-05 11:45:22 +01003876 /* Clear the discovery filter first to free any previously
3877 * allocated memory for the UUID list.
3878 */
3879 hci_discovery_filter_clear(hdev);
3880
Andre Guedes4aab14e2012-02-17 20:39:36 -03003881 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003882 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003883 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3884 hdev->discovery.limited = true;
3885 else
3886 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003887
Johan Hedberg78b781c2016-01-05 13:19:32 +02003888 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003889 if (!cmd) {
3890 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003891 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003892 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003893
Johan Hedberge68f0722015-11-11 08:30:30 +02003894 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003895
3896 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003897 queue_work(hdev->req_workqueue, &hdev->discov_update);
3898 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003899
3900failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003901 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003902 return err;
3903}
3904
Johan Hedberg78b781c2016-01-05 13:19:32 +02003905static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3906 void *data, u16 len)
3907{
3908 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3909 data, len);
3910}
3911
3912static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3913 void *data, u16 len)
3914{
3915 return start_discovery_internal(sk, hdev,
3916 MGMT_OP_START_LIMITED_DISCOVERY,
3917 data, len);
3918}
3919
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003920static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3921 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003922{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003923 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3924 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003925}
3926
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003927static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3928 void *data, u16 len)
3929{
3930 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003931 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003932 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3933 u16 uuid_count, expected_len;
3934 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003935 int err;
3936
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003937 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003938
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003939 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003940
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003941 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003942 err = mgmt_cmd_complete(sk, hdev->id,
3943 MGMT_OP_START_SERVICE_DISCOVERY,
3944 MGMT_STATUS_NOT_POWERED,
3945 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003946 goto failed;
3947 }
3948
3949 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003950 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003951 err = mgmt_cmd_complete(sk, hdev->id,
3952 MGMT_OP_START_SERVICE_DISCOVERY,
3953 MGMT_STATUS_BUSY, &cp->type,
3954 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003955 goto failed;
3956 }
3957
3958 uuid_count = __le16_to_cpu(cp->uuid_count);
3959 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003960 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
3961 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003962 err = mgmt_cmd_complete(sk, hdev->id,
3963 MGMT_OP_START_SERVICE_DISCOVERY,
3964 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3965 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003966 goto failed;
3967 }
3968
3969 expected_len = sizeof(*cp) + uuid_count * 16;
3970 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003971 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
3972 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003973 err = mgmt_cmd_complete(sk, hdev->id,
3974 MGMT_OP_START_SERVICE_DISCOVERY,
3975 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3976 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003977 goto failed;
3978 }
3979
Johan Hedberg591752a2015-11-11 08:11:24 +02003980 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3981 err = mgmt_cmd_complete(sk, hdev->id,
3982 MGMT_OP_START_SERVICE_DISCOVERY,
3983 status, &cp->type, sizeof(cp->type));
3984 goto failed;
3985 }
3986
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003987 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003988 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003989 if (!cmd) {
3990 err = -ENOMEM;
3991 goto failed;
3992 }
3993
Johan Hedberg2922a942014-12-05 13:36:06 +02003994 cmd->cmd_complete = service_discovery_cmd_complete;
3995
Marcel Holtmann22078802014-12-05 11:45:22 +01003996 /* Clear the discovery filter first to free any previously
3997 * allocated memory for the UUID list.
3998 */
3999 hci_discovery_filter_clear(hdev);
4000
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004001 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004002 hdev->discovery.type = cp->type;
4003 hdev->discovery.rssi = cp->rssi;
4004 hdev->discovery.uuid_count = uuid_count;
4005
4006 if (uuid_count > 0) {
4007 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4008 GFP_KERNEL);
4009 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004010 err = mgmt_cmd_complete(sk, hdev->id,
4011 MGMT_OP_START_SERVICE_DISCOVERY,
4012 MGMT_STATUS_FAILED,
4013 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004014 mgmt_pending_remove(cmd);
4015 goto failed;
4016 }
4017 }
4018
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004019 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004020 queue_work(hdev->req_workqueue, &hdev->discov_update);
4021 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004022
4023failed:
4024 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004025 return err;
4026}
4027
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004028void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004029{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004030 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004031
Andre Guedes0e05bba2013-04-30 15:29:33 -03004032 BT_DBG("status %d", status);
4033
4034 hci_dev_lock(hdev);
4035
Johan Hedberg333ae952015-03-17 13:48:47 +02004036 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004037 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004038 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004039 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004040 }
4041
Andre Guedes0e05bba2013-04-30 15:29:33 -03004042 hci_dev_unlock(hdev);
4043}
4044
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004045static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004046 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004047{
Johan Hedbergd9306502012-02-20 23:25:18 +02004048 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004049 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004050 int err;
4051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004052 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004053
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004054 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004055
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004056 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004057 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4058 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4059 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004060 goto unlock;
4061 }
4062
4063 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004064 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4065 MGMT_STATUS_INVALID_PARAMS,
4066 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004067 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004068 }
4069
Johan Hedberg2922a942014-12-05 13:36:06 +02004070 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004071 if (!cmd) {
4072 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004073 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004074 }
4075
Johan Hedberg2922a942014-12-05 13:36:06 +02004076 cmd->cmd_complete = generic_cmd_complete;
4077
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004078 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4079 queue_work(hdev->req_workqueue, &hdev->discov_update);
4080 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004081
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004082unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004083 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004084 return err;
4085}
4086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004087static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004088 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004089{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004090 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004091 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004092 int err;
4093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004094 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004095
Johan Hedberg561aafb2012-01-04 13:31:59 +02004096 hci_dev_lock(hdev);
4097
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004098 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004099 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4100 MGMT_STATUS_FAILED, &cp->addr,
4101 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004102 goto failed;
4103 }
4104
Johan Hedberga198e7b2012-02-17 14:27:06 +02004105 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004106 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004107 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4108 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4109 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004110 goto failed;
4111 }
4112
4113 if (cp->name_known) {
4114 e->name_state = NAME_KNOWN;
4115 list_del(&e->list);
4116 } else {
4117 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004118 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004119 }
4120
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004121 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4122 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004123
4124failed:
4125 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004126 return err;
4127}
4128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004129static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004130 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004131{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004132 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004133 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004134 int err;
4135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004136 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004137
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004138 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004139 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4140 MGMT_STATUS_INVALID_PARAMS,
4141 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004143 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004144
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004145 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4146 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004147 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004148 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004149 goto done;
4150 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004151
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004152 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4153 sk);
4154 status = MGMT_STATUS_SUCCESS;
4155
4156done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004157 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4158 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004159
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004160 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004161
4162 return err;
4163}
4164
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004165static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004166 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004167{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004168 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004169 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004170 int err;
4171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004172 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004173
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004174 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004175 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4176 MGMT_STATUS_INVALID_PARAMS,
4177 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004179 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004180
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004181 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4182 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004183 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004184 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004185 goto done;
4186 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004187
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004188 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4189 sk);
4190 status = MGMT_STATUS_SUCCESS;
4191
4192done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004193 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4194 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004195
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004196 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004197
4198 return err;
4199}
4200
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004201static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4202 u16 len)
4203{
4204 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004205 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004206 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004207 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004208
4209 BT_DBG("%s", hdev->name);
4210
Szymon Jancc72d4b82012-03-16 16:02:57 +01004211 source = __le16_to_cpu(cp->source);
4212
4213 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004214 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4215 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004216
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004217 hci_dev_lock(hdev);
4218
Szymon Jancc72d4b82012-03-16 16:02:57 +01004219 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004220 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4221 hdev->devid_product = __le16_to_cpu(cp->product);
4222 hdev->devid_version = __le16_to_cpu(cp->version);
4223
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004224 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4225 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004226
Johan Hedberg890ea892013-03-15 17:06:52 -05004227 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004228 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004229 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004230
4231 hci_dev_unlock(hdev);
4232
4233 return err;
4234}
4235
Arman Uguray24b4f382015-03-23 15:57:12 -07004236static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4237 u16 opcode)
4238{
4239 BT_DBG("status %d", status);
4240}
4241
Marcel Holtmann1904a852015-01-11 13:50:44 -08004242static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4243 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004244{
4245 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004246 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004247 u8 instance;
4248 struct adv_info *adv_instance;
4249 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004250
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304251 hci_dev_lock(hdev);
4252
Johan Hedberg4375f102013-09-25 13:26:10 +03004253 if (status) {
4254 u8 mgmt_err = mgmt_status(status);
4255
4256 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4257 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304258 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004259 }
4260
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004261 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004262 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004263 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004264 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004265
Johan Hedberg4375f102013-09-25 13:26:10 +03004266 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4267 &match);
4268
4269 new_settings(hdev, match.sk);
4270
4271 if (match.sk)
4272 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304273
Arman Uguray24b4f382015-03-23 15:57:12 -07004274 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004275 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004276 */
4277 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004278 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004279 goto unlock;
4280
Florian Grandel7816b822015-06-18 03:16:45 +02004281 instance = hdev->cur_adv_instance;
4282 if (!instance) {
4283 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4284 struct adv_info, list);
4285 if (!adv_instance)
4286 goto unlock;
4287
4288 instance = adv_instance->instance;
4289 }
4290
Arman Uguray24b4f382015-03-23 15:57:12 -07004291 hci_req_init(&req, hdev);
4292
Johan Hedbergf2252572015-11-18 12:49:20 +02004293 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004294
Florian Grandel7816b822015-06-18 03:16:45 +02004295 if (!err)
4296 err = hci_req_run(&req, enable_advertising_instance);
4297
4298 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004299 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004300
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304301unlock:
4302 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004303}
4304
Marcel Holtmann21b51872013-10-10 09:47:53 -07004305static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4306 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004307{
4308 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004309 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004310 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004311 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004312 int err;
4313
4314 BT_DBG("request for %s", hdev->name);
4315
Johan Hedberge6fe7982013-10-02 15:45:22 +03004316 status = mgmt_le_support(hdev);
4317 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004318 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4319 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004320
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004321 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004322 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4323 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004324
4325 hci_dev_lock(hdev);
4326
4327 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004328
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004329 /* The following conditions are ones which mean that we should
4330 * not do any HCI communication but directly send a mgmt
4331 * response to user space (after toggling the flag if
4332 * necessary).
4333 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004334 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004335 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4336 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004337 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004338 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004339 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004340 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004341
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004342 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004343 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004344 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004345 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004346 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004347 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004348 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004349 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004350 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004351 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004352 }
4353
4354 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4355 if (err < 0)
4356 goto unlock;
4357
4358 if (changed)
4359 err = new_settings(hdev, sk);
4360
4361 goto unlock;
4362 }
4363
Johan Hedberg333ae952015-03-17 13:48:47 +02004364 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4365 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004366 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4367 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004368 goto unlock;
4369 }
4370
4371 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4372 if (!cmd) {
4373 err = -ENOMEM;
4374 goto unlock;
4375 }
4376
4377 hci_req_init(&req, hdev);
4378
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004379 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004380 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004381 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004382 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004383
Florian Grandel7816b822015-06-18 03:16:45 +02004384 cancel_adv_timeout(hdev);
4385
Arman Uguray24b4f382015-03-23 15:57:12 -07004386 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004387 /* Switch to instance "0" for the Set Advertising setting.
4388 * We cannot use update_[adv|scan_rsp]_data() here as the
4389 * HCI_ADVERTISING flag is not yet set.
4390 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004391 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304392
4393 if (ext_adv_capable(hdev)) {
4394 __hci_req_start_ext_adv(&req, 0x00);
4395 } else {
4396 __hci_req_update_adv_data(&req, 0x00);
4397 __hci_req_update_scan_rsp_data(&req, 0x00);
4398 __hci_req_enable_advertising(&req);
4399 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004400 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004401 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004402 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004403
4404 err = hci_req_run(&req, set_advertising_complete);
4405 if (err < 0)
4406 mgmt_pending_remove(cmd);
4407
4408unlock:
4409 hci_dev_unlock(hdev);
4410 return err;
4411}
4412
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004413static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4414 void *data, u16 len)
4415{
4416 struct mgmt_cp_set_static_address *cp = data;
4417 int err;
4418
4419 BT_DBG("%s", hdev->name);
4420
Marcel Holtmann62af4442013-10-02 22:10:32 -07004421 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004422 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4423 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004424
4425 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004426 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4427 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004428
4429 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4430 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004431 return mgmt_cmd_status(sk, hdev->id,
4432 MGMT_OP_SET_STATIC_ADDRESS,
4433 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004434
4435 /* Two most significant bits shall be set */
4436 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004437 return mgmt_cmd_status(sk, hdev->id,
4438 MGMT_OP_SET_STATIC_ADDRESS,
4439 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004440 }
4441
4442 hci_dev_lock(hdev);
4443
4444 bacpy(&hdev->static_addr, &cp->bdaddr);
4445
Marcel Holtmann93690c22015-03-06 10:11:21 -08004446 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4447 if (err < 0)
4448 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004449
Marcel Holtmann93690c22015-03-06 10:11:21 -08004450 err = new_settings(hdev, sk);
4451
4452unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004453 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004454 return err;
4455}
4456
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004457static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4458 void *data, u16 len)
4459{
4460 struct mgmt_cp_set_scan_params *cp = data;
4461 __u16 interval, window;
4462 int err;
4463
4464 BT_DBG("%s", hdev->name);
4465
4466 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004467 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4468 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004469
4470 interval = __le16_to_cpu(cp->interval);
4471
4472 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004473 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4474 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004475
4476 window = __le16_to_cpu(cp->window);
4477
4478 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004479 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4480 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004481
Marcel Holtmann899e1072013-10-14 09:55:32 -07004482 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004483 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4484 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004485
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004486 hci_dev_lock(hdev);
4487
4488 hdev->le_scan_interval = interval;
4489 hdev->le_scan_window = window;
4490
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004491 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4492 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004493
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004494 /* If background scan is running, restart it so new parameters are
4495 * loaded.
4496 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004497 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004498 hdev->discovery.state == DISCOVERY_STOPPED) {
4499 struct hci_request req;
4500
4501 hci_req_init(&req, hdev);
4502
4503 hci_req_add_le_scan_disable(&req);
4504 hci_req_add_le_passive_scan(&req);
4505
4506 hci_req_run(&req, NULL);
4507 }
4508
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004509 hci_dev_unlock(hdev);
4510
4511 return err;
4512}
4513
Marcel Holtmann1904a852015-01-11 13:50:44 -08004514static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4515 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004516{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004517 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004518
4519 BT_DBG("status 0x%02x", status);
4520
4521 hci_dev_lock(hdev);
4522
Johan Hedberg333ae952015-03-17 13:48:47 +02004523 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004524 if (!cmd)
4525 goto unlock;
4526
4527 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004528 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4529 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004530 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004531 struct mgmt_mode *cp = cmd->param;
4532
4533 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004534 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004535 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004536 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004537
Johan Hedberg33e38b32013-03-15 17:07:05 -05004538 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4539 new_settings(hdev, cmd->sk);
4540 }
4541
4542 mgmt_pending_remove(cmd);
4543
4544unlock:
4545 hci_dev_unlock(hdev);
4546}
4547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004548static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004549 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004550{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004551 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004552 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004553 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004554 int err;
4555
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004556 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004557
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004558 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004559 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004560 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4561 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004562
Johan Hedberga7e80f22013-01-09 16:05:19 +02004563 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004564 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4565 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004566
Antti Julkuf6422ec2011-06-22 13:11:56 +03004567 hci_dev_lock(hdev);
4568
Johan Hedberg333ae952015-03-17 13:48:47 +02004569 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004570 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4571 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004572 goto unlock;
4573 }
4574
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004575 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004576 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4577 hdev);
4578 goto unlock;
4579 }
4580
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004581 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004582 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004583 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4584 hdev);
4585 new_settings(hdev, sk);
4586 goto unlock;
4587 }
4588
Johan Hedberg33e38b32013-03-15 17:07:05 -05004589 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4590 data, len);
4591 if (!cmd) {
4592 err = -ENOMEM;
4593 goto unlock;
4594 }
4595
4596 hci_req_init(&req, hdev);
4597
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004598 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004599
4600 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004601 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004602 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4603 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004604 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004605 }
4606
Johan Hedberg33e38b32013-03-15 17:07:05 -05004607unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004608 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004609
Antti Julkuf6422ec2011-06-22 13:11:56 +03004610 return err;
4611}
4612
Marcel Holtmann1904a852015-01-11 13:50:44 -08004613static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004614{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004615 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004616
4617 BT_DBG("status 0x%02x", status);
4618
4619 hci_dev_lock(hdev);
4620
Johan Hedberg333ae952015-03-17 13:48:47 +02004621 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004622 if (!cmd)
4623 goto unlock;
4624
4625 if (status) {
4626 u8 mgmt_err = mgmt_status(status);
4627
4628 /* We need to restore the flag if related HCI commands
4629 * failed.
4630 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004631 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004632
Johan Hedberga69e8372015-03-06 21:08:53 +02004633 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004634 } else {
4635 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4636 new_settings(hdev, cmd->sk);
4637 }
4638
4639 mgmt_pending_remove(cmd);
4640
4641unlock:
4642 hci_dev_unlock(hdev);
4643}
4644
4645static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4646{
4647 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004648 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004649 struct hci_request req;
4650 int err;
4651
4652 BT_DBG("request for %s", hdev->name);
4653
4654 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004655 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4656 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004657
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004658 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004659 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4660 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004661
4662 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004663 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4664 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004665
4666 hci_dev_lock(hdev);
4667
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004668 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004669 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4670 goto unlock;
4671 }
4672
4673 if (!hdev_is_powered(hdev)) {
4674 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004675 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4676 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4677 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4678 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4679 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004680 }
4681
Marcel Holtmannce05d602015-03-13 02:11:03 -07004682 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004683
4684 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4685 if (err < 0)
4686 goto unlock;
4687
4688 err = new_settings(hdev, sk);
4689 goto unlock;
4690 }
4691
4692 /* Reject disabling when powered on */
4693 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004694 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4695 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004696 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004697 } else {
4698 /* When configuring a dual-mode controller to operate
4699 * with LE only and using a static address, then switching
4700 * BR/EDR back on is not allowed.
4701 *
4702 * Dual-mode controllers shall operate with the public
4703 * address as its identity address for BR/EDR and LE. So
4704 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004705 *
4706 * The same restrictions applies when secure connections
4707 * has been enabled. For BR/EDR this is a controller feature
4708 * while for LE it is a host stack feature. This means that
4709 * switching BR/EDR back on when secure connections has been
4710 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004711 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004712 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004713 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004714 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004715 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4716 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004717 goto unlock;
4718 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004719 }
4720
Johan Hedberg333ae952015-03-17 13:48:47 +02004721 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004722 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4723 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004724 goto unlock;
4725 }
4726
4727 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4728 if (!cmd) {
4729 err = -ENOMEM;
4730 goto unlock;
4731 }
4732
Johan Hedbergf2252572015-11-18 12:49:20 +02004733 /* We need to flip the bit already here so that
4734 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004735 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004736 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004737
4738 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004739
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004740 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004741 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004742
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004743 /* Since only the advertising data flags will change, there
4744 * is no need to update the scan response data.
4745 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004746 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004747
Johan Hedberg0663ca22013-10-02 13:43:14 +03004748 err = hci_req_run(&req, set_bredr_complete);
4749 if (err < 0)
4750 mgmt_pending_remove(cmd);
4751
4752unlock:
4753 hci_dev_unlock(hdev);
4754 return err;
4755}
4756
Johan Hedberga1443f52015-01-23 15:42:46 +02004757static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4758{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004759 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004760 struct mgmt_mode *cp;
4761
4762 BT_DBG("%s status %u", hdev->name, status);
4763
4764 hci_dev_lock(hdev);
4765
Johan Hedberg333ae952015-03-17 13:48:47 +02004766 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004767 if (!cmd)
4768 goto unlock;
4769
4770 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004771 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4772 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004773 goto remove;
4774 }
4775
4776 cp = cmd->param;
4777
4778 switch (cp->val) {
4779 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004780 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4781 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004782 break;
4783 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004784 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004785 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004786 break;
4787 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004788 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4789 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004790 break;
4791 }
4792
4793 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4794 new_settings(hdev, cmd->sk);
4795
4796remove:
4797 mgmt_pending_remove(cmd);
4798unlock:
4799 hci_dev_unlock(hdev);
4800}
4801
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004802static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4803 void *data, u16 len)
4804{
4805 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004806 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004807 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004808 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004809 int err;
4810
4811 BT_DBG("request for %s", hdev->name);
4812
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004813 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004814 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004815 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4816 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004817
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004818 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004819 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004820 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004821 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4822 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004823
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004824 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004825 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004826 MGMT_STATUS_INVALID_PARAMS);
4827
4828 hci_dev_lock(hdev);
4829
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004830 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004831 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004832 bool changed;
4833
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004834 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004835 changed = !hci_dev_test_and_set_flag(hdev,
4836 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004837 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004838 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004839 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004840 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004841 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004842 changed = hci_dev_test_and_clear_flag(hdev,
4843 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004844 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004845 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004846
4847 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4848 if (err < 0)
4849 goto failed;
4850
4851 if (changed)
4852 err = new_settings(hdev, sk);
4853
4854 goto failed;
4855 }
4856
Johan Hedberg333ae952015-03-17 13:48:47 +02004857 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004858 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4859 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004860 goto failed;
4861 }
4862
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004863 val = !!cp->val;
4864
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004865 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4866 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004867 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4868 goto failed;
4869 }
4870
4871 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4872 if (!cmd) {
4873 err = -ENOMEM;
4874 goto failed;
4875 }
4876
Johan Hedberga1443f52015-01-23 15:42:46 +02004877 hci_req_init(&req, hdev);
4878 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4879 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004880 if (err < 0) {
4881 mgmt_pending_remove(cmd);
4882 goto failed;
4883 }
4884
4885failed:
4886 hci_dev_unlock(hdev);
4887 return err;
4888}
4889
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004890static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4891 void *data, u16 len)
4892{
4893 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004894 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004895 int err;
4896
4897 BT_DBG("request for %s", hdev->name);
4898
Johan Hedbergb97109792014-06-24 14:00:28 +03004899 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004900 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4901 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004902
4903 hci_dev_lock(hdev);
4904
4905 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004906 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004907 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004908 changed = hci_dev_test_and_clear_flag(hdev,
4909 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004910
Johan Hedbergb97109792014-06-24 14:00:28 +03004911 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004912 use_changed = !hci_dev_test_and_set_flag(hdev,
4913 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004914 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004915 use_changed = hci_dev_test_and_clear_flag(hdev,
4916 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004917
4918 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004919 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004920 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4921 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4922 sizeof(mode), &mode);
4923 }
4924
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004925 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4926 if (err < 0)
4927 goto unlock;
4928
4929 if (changed)
4930 err = new_settings(hdev, sk);
4931
4932unlock:
4933 hci_dev_unlock(hdev);
4934 return err;
4935}
4936
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004937static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4938 u16 len)
4939{
4940 struct mgmt_cp_set_privacy *cp = cp_data;
4941 bool changed;
4942 int err;
4943
4944 BT_DBG("request for %s", hdev->name);
4945
4946 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004947 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4948 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004949
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004950 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004951 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4952 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004953
4954 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004955 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4956 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004957
4958 hci_dev_lock(hdev);
4959
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004960 /* If user space supports this command it is also expected to
4961 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4962 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004963 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004964
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004965 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004966 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004967 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004968 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05304969 hci_adv_instances_set_rpa_expired(hdev, true);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004970 if (cp->privacy == 0x02)
4971 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4972 else
4973 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004974 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004975 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004976 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004977 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Jaganath Kanakkasserya73c0462018-07-19 17:09:45 +05304978 hci_adv_instances_set_rpa_expired(hdev, false);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004979 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004980 }
4981
4982 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4983 if (err < 0)
4984 goto unlock;
4985
4986 if (changed)
4987 err = new_settings(hdev, sk);
4988
4989unlock:
4990 hci_dev_unlock(hdev);
4991 return err;
4992}
4993
Johan Hedberg41edf162014-02-18 10:19:35 +02004994static bool irk_is_valid(struct mgmt_irk_info *irk)
4995{
4996 switch (irk->addr.type) {
4997 case BDADDR_LE_PUBLIC:
4998 return true;
4999
5000 case BDADDR_LE_RANDOM:
5001 /* Two most significant bits shall be set */
5002 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5003 return false;
5004 return true;
5005 }
5006
5007 return false;
5008}
5009
5010static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5011 u16 len)
5012{
5013 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005014 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5015 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005016 u16 irk_count, expected_len;
5017 int i, err;
5018
5019 BT_DBG("request for %s", hdev->name);
5020
5021 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005022 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5023 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005024
5025 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005026 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005027 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5028 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005029 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5030 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005031 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005032
5033 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5034 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005035 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5036 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005037 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5038 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005039 }
5040
5041 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5042
5043 for (i = 0; i < irk_count; i++) {
5044 struct mgmt_irk_info *key = &cp->irks[i];
5045
5046 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005047 return mgmt_cmd_status(sk, hdev->id,
5048 MGMT_OP_LOAD_IRKS,
5049 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005050 }
5051
5052 hci_dev_lock(hdev);
5053
5054 hci_smp_irks_clear(hdev);
5055
5056 for (i = 0; i < irk_count; i++) {
5057 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005058
Johan Hedberg85813a72015-10-21 18:02:59 +03005059 hci_add_irk(hdev, &irk->addr.bdaddr,
5060 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005061 BDADDR_ANY);
5062 }
5063
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005064 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005065
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005066 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005067
5068 hci_dev_unlock(hdev);
5069
5070 return err;
5071}
5072
Johan Hedberg3f706b72013-01-20 14:27:16 +02005073static bool ltk_is_valid(struct mgmt_ltk_info *key)
5074{
5075 if (key->master != 0x00 && key->master != 0x01)
5076 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005077
5078 switch (key->addr.type) {
5079 case BDADDR_LE_PUBLIC:
5080 return true;
5081
5082 case BDADDR_LE_RANDOM:
5083 /* Two most significant bits shall be set */
5084 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5085 return false;
5086 return true;
5087 }
5088
5089 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005090}
5091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005092static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005093 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005094{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005095 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005096 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5097 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005098 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005099 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005100
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005101 BT_DBG("request for %s", hdev->name);
5102
5103 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005104 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5105 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005106
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005107 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005108 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005109 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5110 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005111 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5112 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005113 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005114
5115 expected_len = sizeof(*cp) + key_count *
5116 sizeof(struct mgmt_ltk_info);
5117 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005118 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5119 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005120 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5121 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005122 }
5123
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005124 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005125
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005126 for (i = 0; i < key_count; i++) {
5127 struct mgmt_ltk_info *key = &cp->keys[i];
5128
Johan Hedberg3f706b72013-01-20 14:27:16 +02005129 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005130 return mgmt_cmd_status(sk, hdev->id,
5131 MGMT_OP_LOAD_LONG_TERM_KEYS,
5132 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005133 }
5134
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005135 hci_dev_lock(hdev);
5136
5137 hci_smp_ltks_clear(hdev);
5138
5139 for (i = 0; i < key_count; i++) {
5140 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005141 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005142
Johan Hedberg61b43352014-05-29 19:36:53 +03005143 switch (key->type) {
5144 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005145 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005146 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005147 break;
5148 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005149 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005150 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005151 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005152 case MGMT_LTK_P256_UNAUTH:
5153 authenticated = 0x00;
5154 type = SMP_LTK_P256;
5155 break;
5156 case MGMT_LTK_P256_AUTH:
5157 authenticated = 0x01;
5158 type = SMP_LTK_P256;
5159 break;
5160 case MGMT_LTK_P256_DEBUG:
5161 authenticated = 0x00;
5162 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005163 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005164 default:
5165 continue;
5166 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005167
Johan Hedberg85813a72015-10-21 18:02:59 +03005168 hci_add_ltk(hdev, &key->addr.bdaddr,
5169 le_addr_type(key->addr.type), type, authenticated,
5170 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005171 }
5172
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005173 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005174 NULL, 0);
5175
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005176 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005177
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005178 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005179}
5180
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005181static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005182{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005183 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005184 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005185 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005186
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005187 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005188
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005189 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005190 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005191 rp.tx_power = conn->tx_power;
5192 rp.max_tx_power = conn->max_tx_power;
5193 } else {
5194 rp.rssi = HCI_RSSI_INVALID;
5195 rp.tx_power = HCI_TX_POWER_INVALID;
5196 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005197 }
5198
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005199 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5200 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005201
5202 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005203 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005204
5205 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005206}
5207
Marcel Holtmann1904a852015-01-11 13:50:44 -08005208static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5209 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005210{
5211 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005212 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005213 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005214 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005215 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005216
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005217 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005218
5219 hci_dev_lock(hdev);
5220
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005221 /* Commands sent in request are either Read RSSI or Read Transmit Power
5222 * Level so we check which one was last sent to retrieve connection
5223 * handle. Both commands have handle as first parameter so it's safe to
5224 * cast data on the same command struct.
5225 *
5226 * First command sent is always Read RSSI and we fail only if it fails.
5227 * In other case we simply override error to indicate success as we
5228 * already remembered if TX power value is actually valid.
5229 */
5230 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5231 if (!cp) {
5232 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005233 status = MGMT_STATUS_SUCCESS;
5234 } else {
5235 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005236 }
5237
5238 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005239 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005240 goto unlock;
5241 }
5242
5243 handle = __le16_to_cpu(cp->handle);
5244 conn = hci_conn_hash_lookup_handle(hdev, handle);
5245 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005246 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5247 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005248 goto unlock;
5249 }
5250
Johan Hedberg333ae952015-03-17 13:48:47 +02005251 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005252 if (!cmd)
5253 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005254
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005255 cmd->cmd_complete(cmd, status);
5256 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005257
5258unlock:
5259 hci_dev_unlock(hdev);
5260}
5261
5262static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5263 u16 len)
5264{
5265 struct mgmt_cp_get_conn_info *cp = data;
5266 struct mgmt_rp_get_conn_info rp;
5267 struct hci_conn *conn;
5268 unsigned long conn_info_age;
5269 int err = 0;
5270
5271 BT_DBG("%s", hdev->name);
5272
5273 memset(&rp, 0, sizeof(rp));
5274 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5275 rp.addr.type = cp->addr.type;
5276
5277 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005278 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5279 MGMT_STATUS_INVALID_PARAMS,
5280 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005281
5282 hci_dev_lock(hdev);
5283
5284 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005285 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5286 MGMT_STATUS_NOT_POWERED, &rp,
5287 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005288 goto unlock;
5289 }
5290
5291 if (cp->addr.type == BDADDR_BREDR)
5292 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5293 &cp->addr.bdaddr);
5294 else
5295 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5296
5297 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005298 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5299 MGMT_STATUS_NOT_CONNECTED, &rp,
5300 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005301 goto unlock;
5302 }
5303
Johan Hedberg333ae952015-03-17 13:48:47 +02005304 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005305 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5306 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005307 goto unlock;
5308 }
5309
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005310 /* To avoid client trying to guess when to poll again for information we
5311 * calculate conn info age as random value between min/max set in hdev.
5312 */
5313 conn_info_age = hdev->conn_info_min_age +
5314 prandom_u32_max(hdev->conn_info_max_age -
5315 hdev->conn_info_min_age);
5316
5317 /* Query controller to refresh cached values if they are too old or were
5318 * never read.
5319 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005320 if (time_after(jiffies, conn->conn_info_timestamp +
5321 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005322 !conn->conn_info_timestamp) {
5323 struct hci_request req;
5324 struct hci_cp_read_tx_power req_txp_cp;
5325 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005326 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005327
5328 hci_req_init(&req, hdev);
5329 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5330 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5331 &req_rssi_cp);
5332
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005333 /* For LE links TX power does not change thus we don't need to
5334 * query for it once value is known.
5335 */
5336 if (!bdaddr_type_is_le(cp->addr.type) ||
5337 conn->tx_power == HCI_TX_POWER_INVALID) {
5338 req_txp_cp.handle = cpu_to_le16(conn->handle);
5339 req_txp_cp.type = 0x00;
5340 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5341 sizeof(req_txp_cp), &req_txp_cp);
5342 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005343
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005344 /* Max TX power needs to be read only once per connection */
5345 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5346 req_txp_cp.handle = cpu_to_le16(conn->handle);
5347 req_txp_cp.type = 0x01;
5348 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5349 sizeof(req_txp_cp), &req_txp_cp);
5350 }
5351
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005352 err = hci_req_run(&req, conn_info_refresh_complete);
5353 if (err < 0)
5354 goto unlock;
5355
5356 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5357 data, len);
5358 if (!cmd) {
5359 err = -ENOMEM;
5360 goto unlock;
5361 }
5362
5363 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005364 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005365 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005366
5367 conn->conn_info_timestamp = jiffies;
5368 } else {
5369 /* Cache is valid, just reply with values cached in hci_conn */
5370 rp.rssi = conn->rssi;
5371 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005372 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005373
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005374 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5375 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005376 }
5377
5378unlock:
5379 hci_dev_unlock(hdev);
5380 return err;
5381}
5382
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005383static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005384{
5385 struct hci_conn *conn = cmd->user_data;
5386 struct mgmt_rp_get_clock_info rp;
5387 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005388 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005389
5390 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005391 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005392
5393 if (status)
5394 goto complete;
5395
5396 hdev = hci_dev_get(cmd->index);
5397 if (hdev) {
5398 rp.local_clock = cpu_to_le32(hdev->clock);
5399 hci_dev_put(hdev);
5400 }
5401
5402 if (conn) {
5403 rp.piconet_clock = cpu_to_le32(conn->clock);
5404 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5405 }
5406
5407complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005408 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5409 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005410
5411 if (conn) {
5412 hci_conn_drop(conn);
5413 hci_conn_put(conn);
5414 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005415
5416 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005417}
5418
Marcel Holtmann1904a852015-01-11 13:50:44 -08005419static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005420{
Johan Hedberg95868422014-06-28 17:54:07 +03005421 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005422 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005423 struct hci_conn *conn;
5424
5425 BT_DBG("%s status %u", hdev->name, status);
5426
5427 hci_dev_lock(hdev);
5428
5429 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5430 if (!hci_cp)
5431 goto unlock;
5432
5433 if (hci_cp->which) {
5434 u16 handle = __le16_to_cpu(hci_cp->handle);
5435 conn = hci_conn_hash_lookup_handle(hdev, handle);
5436 } else {
5437 conn = NULL;
5438 }
5439
Johan Hedberg333ae952015-03-17 13:48:47 +02005440 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005441 if (!cmd)
5442 goto unlock;
5443
Johan Hedberg69487372014-12-05 13:36:07 +02005444 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005445 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005446
5447unlock:
5448 hci_dev_unlock(hdev);
5449}
5450
5451static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5452 u16 len)
5453{
5454 struct mgmt_cp_get_clock_info *cp = data;
5455 struct mgmt_rp_get_clock_info rp;
5456 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005457 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005458 struct hci_request req;
5459 struct hci_conn *conn;
5460 int err;
5461
5462 BT_DBG("%s", hdev->name);
5463
5464 memset(&rp, 0, sizeof(rp));
5465 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5466 rp.addr.type = cp->addr.type;
5467
5468 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005469 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5470 MGMT_STATUS_INVALID_PARAMS,
5471 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005472
5473 hci_dev_lock(hdev);
5474
5475 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005476 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5477 MGMT_STATUS_NOT_POWERED, &rp,
5478 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005479 goto unlock;
5480 }
5481
5482 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5483 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5484 &cp->addr.bdaddr);
5485 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005486 err = mgmt_cmd_complete(sk, hdev->id,
5487 MGMT_OP_GET_CLOCK_INFO,
5488 MGMT_STATUS_NOT_CONNECTED,
5489 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005490 goto unlock;
5491 }
5492 } else {
5493 conn = NULL;
5494 }
5495
5496 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5497 if (!cmd) {
5498 err = -ENOMEM;
5499 goto unlock;
5500 }
5501
Johan Hedberg69487372014-12-05 13:36:07 +02005502 cmd->cmd_complete = clock_info_cmd_complete;
5503
Johan Hedberg95868422014-06-28 17:54:07 +03005504 hci_req_init(&req, hdev);
5505
5506 memset(&hci_cp, 0, sizeof(hci_cp));
5507 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5508
5509 if (conn) {
5510 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005511 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005512
5513 hci_cp.handle = cpu_to_le16(conn->handle);
5514 hci_cp.which = 0x01; /* Piconet clock */
5515 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5516 }
5517
5518 err = hci_req_run(&req, get_clock_info_complete);
5519 if (err < 0)
5520 mgmt_pending_remove(cmd);
5521
5522unlock:
5523 hci_dev_unlock(hdev);
5524 return err;
5525}
5526
Johan Hedberg5a154e62014-12-19 22:26:02 +02005527static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5528{
5529 struct hci_conn *conn;
5530
5531 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5532 if (!conn)
5533 return false;
5534
5535 if (conn->dst_type != type)
5536 return false;
5537
5538 if (conn->state != BT_CONNECTED)
5539 return false;
5540
5541 return true;
5542}
5543
5544/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005545static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005546 u8 addr_type, u8 auto_connect)
5547{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005548 struct hci_conn_params *params;
5549
5550 params = hci_conn_params_add(hdev, addr, addr_type);
5551 if (!params)
5552 return -EIO;
5553
5554 if (params->auto_connect == auto_connect)
5555 return 0;
5556
5557 list_del_init(&params->action);
5558
5559 switch (auto_connect) {
5560 case HCI_AUTO_CONN_DISABLED:
5561 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005562 /* If auto connect is being disabled when we're trying to
5563 * connect to device, keep connecting.
5564 */
5565 if (params->explicit_connect)
5566 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005567 break;
5568 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005569 if (params->explicit_connect)
5570 list_add(&params->action, &hdev->pend_le_conns);
5571 else
5572 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005573 break;
5574 case HCI_AUTO_CONN_DIRECT:
5575 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005576 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005577 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005578 break;
5579 }
5580
5581 params->auto_connect = auto_connect;
5582
5583 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5584 auto_connect);
5585
5586 return 0;
5587}
5588
Marcel Holtmann8afef092014-06-29 22:28:34 +02005589static void device_added(struct sock *sk, struct hci_dev *hdev,
5590 bdaddr_t *bdaddr, u8 type, u8 action)
5591{
5592 struct mgmt_ev_device_added ev;
5593
5594 bacpy(&ev.addr.bdaddr, bdaddr);
5595 ev.addr.type = type;
5596 ev.action = action;
5597
5598 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5599}
5600
Marcel Holtmann2faade52014-06-29 19:44:03 +02005601static int add_device(struct sock *sk, struct hci_dev *hdev,
5602 void *data, u16 len)
5603{
5604 struct mgmt_cp_add_device *cp = data;
5605 u8 auto_conn, addr_type;
5606 int err;
5607
5608 BT_DBG("%s", hdev->name);
5609
Johan Hedberg66593582014-07-09 12:59:14 +03005610 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005611 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005612 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5613 MGMT_STATUS_INVALID_PARAMS,
5614 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005615
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005616 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005617 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5618 MGMT_STATUS_INVALID_PARAMS,
5619 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005620
5621 hci_dev_lock(hdev);
5622
Johan Hedberg66593582014-07-09 12:59:14 +03005623 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005624 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005625 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005626 err = mgmt_cmd_complete(sk, hdev->id,
5627 MGMT_OP_ADD_DEVICE,
5628 MGMT_STATUS_INVALID_PARAMS,
5629 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005630 goto unlock;
5631 }
5632
5633 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5634 cp->addr.type);
5635 if (err)
5636 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005637
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005638 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005639
Johan Hedberg66593582014-07-09 12:59:14 +03005640 goto added;
5641 }
5642
Johan Hedberg85813a72015-10-21 18:02:59 +03005643 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005644
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005645 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005646 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005647 else if (cp->action == 0x01)
5648 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005649 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005650 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005651
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005652 /* Kernel internally uses conn_params with resolvable private
5653 * address, but Add Device allows only identity addresses.
5654 * Make sure it is enforced before calling
5655 * hci_conn_params_lookup.
5656 */
5657 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005658 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5659 MGMT_STATUS_INVALID_PARAMS,
5660 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005661 goto unlock;
5662 }
5663
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005664 /* If the connection parameters don't exist for this device,
5665 * they will be created and configured with defaults.
5666 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005667 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005668 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005669 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5670 MGMT_STATUS_FAILED, &cp->addr,
5671 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005672 goto unlock;
5673 }
5674
Johan Hedberg51d7a942015-11-11 08:11:18 +02005675 hci_update_background_scan(hdev);
5676
Johan Hedberg66593582014-07-09 12:59:14 +03005677added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005678 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5679
Johan Hedberg51d7a942015-11-11 08:11:18 +02005680 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5681 MGMT_STATUS_SUCCESS, &cp->addr,
5682 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005683
5684unlock:
5685 hci_dev_unlock(hdev);
5686 return err;
5687}
5688
Marcel Holtmann8afef092014-06-29 22:28:34 +02005689static void device_removed(struct sock *sk, struct hci_dev *hdev,
5690 bdaddr_t *bdaddr, u8 type)
5691{
5692 struct mgmt_ev_device_removed ev;
5693
5694 bacpy(&ev.addr.bdaddr, bdaddr);
5695 ev.addr.type = type;
5696
5697 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5698}
5699
Marcel Holtmann2faade52014-06-29 19:44:03 +02005700static int remove_device(struct sock *sk, struct hci_dev *hdev,
5701 void *data, u16 len)
5702{
5703 struct mgmt_cp_remove_device *cp = data;
5704 int err;
5705
5706 BT_DBG("%s", hdev->name);
5707
5708 hci_dev_lock(hdev);
5709
5710 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005711 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005712 u8 addr_type;
5713
Johan Hedberg66593582014-07-09 12:59:14 +03005714 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005715 err = mgmt_cmd_complete(sk, hdev->id,
5716 MGMT_OP_REMOVE_DEVICE,
5717 MGMT_STATUS_INVALID_PARAMS,
5718 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005719 goto unlock;
5720 }
5721
Johan Hedberg66593582014-07-09 12:59:14 +03005722 if (cp->addr.type == BDADDR_BREDR) {
5723 err = hci_bdaddr_list_del(&hdev->whitelist,
5724 &cp->addr.bdaddr,
5725 cp->addr.type);
5726 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005727 err = mgmt_cmd_complete(sk, hdev->id,
5728 MGMT_OP_REMOVE_DEVICE,
5729 MGMT_STATUS_INVALID_PARAMS,
5730 &cp->addr,
5731 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005732 goto unlock;
5733 }
5734
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005735 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005736
Johan Hedberg66593582014-07-09 12:59:14 +03005737 device_removed(sk, hdev, &cp->addr.bdaddr,
5738 cp->addr.type);
5739 goto complete;
5740 }
5741
Johan Hedberg85813a72015-10-21 18:02:59 +03005742 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005743
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005744 /* Kernel internally uses conn_params with resolvable private
5745 * address, but Remove Device allows only identity addresses.
5746 * Make sure it is enforced before calling
5747 * hci_conn_params_lookup.
5748 */
5749 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005750 err = mgmt_cmd_complete(sk, hdev->id,
5751 MGMT_OP_REMOVE_DEVICE,
5752 MGMT_STATUS_INVALID_PARAMS,
5753 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005754 goto unlock;
5755 }
5756
Johan Hedbergc71593d2014-07-02 17:37:28 +03005757 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5758 addr_type);
5759 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005760 err = mgmt_cmd_complete(sk, hdev->id,
5761 MGMT_OP_REMOVE_DEVICE,
5762 MGMT_STATUS_INVALID_PARAMS,
5763 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005764 goto unlock;
5765 }
5766
Johan Hedberg679d2b62015-10-16 10:07:52 +03005767 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5768 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005769 err = mgmt_cmd_complete(sk, hdev->id,
5770 MGMT_OP_REMOVE_DEVICE,
5771 MGMT_STATUS_INVALID_PARAMS,
5772 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005773 goto unlock;
5774 }
5775
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005776 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005777 list_del(&params->list);
5778 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005779 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005780
5781 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005782 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005783 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005784 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005785
Marcel Holtmann2faade52014-06-29 19:44:03 +02005786 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005787 err = mgmt_cmd_complete(sk, hdev->id,
5788 MGMT_OP_REMOVE_DEVICE,
5789 MGMT_STATUS_INVALID_PARAMS,
5790 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005791 goto unlock;
5792 }
5793
Johan Hedberg66593582014-07-09 12:59:14 +03005794 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5795 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5796 list_del(&b->list);
5797 kfree(b);
5798 }
5799
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005800 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005801
Johan Hedberg19de0822014-07-06 13:06:51 +03005802 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5803 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5804 continue;
5805 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005806 if (p->explicit_connect) {
5807 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5808 continue;
5809 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005810 list_del(&p->action);
5811 list_del(&p->list);
5812 kfree(p);
5813 }
5814
5815 BT_DBG("All LE connection parameters were removed");
5816
Johan Hedberg51d7a942015-11-11 08:11:18 +02005817 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005818 }
5819
Johan Hedberg66593582014-07-09 12:59:14 +03005820complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005821 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5822 MGMT_STATUS_SUCCESS, &cp->addr,
5823 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005824unlock:
5825 hci_dev_unlock(hdev);
5826 return err;
5827}
5828
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005829static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5830 u16 len)
5831{
5832 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005833 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5834 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005835 u16 param_count, expected_len;
5836 int i;
5837
5838 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005839 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5840 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005841
5842 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005843 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005844 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
5845 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005846 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5847 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005848 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005849
5850 expected_len = sizeof(*cp) + param_count *
5851 sizeof(struct mgmt_conn_param);
5852 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005853 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
5854 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005855 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5856 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005857 }
5858
5859 BT_DBG("%s param_count %u", hdev->name, param_count);
5860
5861 hci_dev_lock(hdev);
5862
5863 hci_conn_params_clear_disabled(hdev);
5864
5865 for (i = 0; i < param_count; i++) {
5866 struct mgmt_conn_param *param = &cp->params[i];
5867 struct hci_conn_params *hci_param;
5868 u16 min, max, latency, timeout;
5869 u8 addr_type;
5870
5871 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5872 param->addr.type);
5873
5874 if (param->addr.type == BDADDR_LE_PUBLIC) {
5875 addr_type = ADDR_LE_DEV_PUBLIC;
5876 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5877 addr_type = ADDR_LE_DEV_RANDOM;
5878 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005879 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005880 continue;
5881 }
5882
5883 min = le16_to_cpu(param->min_interval);
5884 max = le16_to_cpu(param->max_interval);
5885 latency = le16_to_cpu(param->latency);
5886 timeout = le16_to_cpu(param->timeout);
5887
5888 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5889 min, max, latency, timeout);
5890
5891 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005892 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005893 continue;
5894 }
5895
5896 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5897 addr_type);
5898 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005899 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005900 continue;
5901 }
5902
5903 hci_param->conn_min_interval = min;
5904 hci_param->conn_max_interval = max;
5905 hci_param->conn_latency = latency;
5906 hci_param->supervision_timeout = timeout;
5907 }
5908
5909 hci_dev_unlock(hdev);
5910
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005911 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5912 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005913}
5914
Marcel Holtmanndbece372014-07-04 18:11:55 +02005915static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5916 void *data, u16 len)
5917{
5918 struct mgmt_cp_set_external_config *cp = data;
5919 bool changed;
5920 int err;
5921
5922 BT_DBG("%s", hdev->name);
5923
5924 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005925 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5926 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005927
5928 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005929 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5930 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005931
5932 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005933 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5934 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005935
5936 hci_dev_lock(hdev);
5937
5938 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005939 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005940 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005941 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005942
5943 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5944 if (err < 0)
5945 goto unlock;
5946
5947 if (!changed)
5948 goto unlock;
5949
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005950 err = new_options(hdev, sk);
5951
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005952 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005953 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005954
Marcel Holtmann516018a2015-03-13 02:11:04 -07005955 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005956 hci_dev_set_flag(hdev, HCI_CONFIG);
5957 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005958
5959 queue_work(hdev->req_workqueue, &hdev->power_on);
5960 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005961 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005962 mgmt_index_added(hdev);
5963 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005964 }
5965
5966unlock:
5967 hci_dev_unlock(hdev);
5968 return err;
5969}
5970
Marcel Holtmann9713c172014-07-06 12:11:15 +02005971static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5972 void *data, u16 len)
5973{
5974 struct mgmt_cp_set_public_address *cp = data;
5975 bool changed;
5976 int err;
5977
5978 BT_DBG("%s", hdev->name);
5979
5980 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005981 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5982 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005983
5984 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005985 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5986 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005987
5988 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005989 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5990 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005991
5992 hci_dev_lock(hdev);
5993
5994 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5995 bacpy(&hdev->public_addr, &cp->bdaddr);
5996
5997 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5998 if (err < 0)
5999 goto unlock;
6000
6001 if (!changed)
6002 goto unlock;
6003
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006004 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006005 err = new_options(hdev, sk);
6006
6007 if (is_configured(hdev)) {
6008 mgmt_index_removed(hdev);
6009
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006010 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006011
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006012 hci_dev_set_flag(hdev, HCI_CONFIG);
6013 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006014
6015 queue_work(hdev->req_workqueue, &hdev->power_on);
6016 }
6017
6018unlock:
6019 hci_dev_unlock(hdev);
6020 return err;
6021}
6022
Johan Hedberg40f66c02015-04-07 21:52:22 +03006023static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6024 u16 opcode, struct sk_buff *skb)
6025{
6026 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6027 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6028 u8 *h192, *r192, *h256, *r256;
6029 struct mgmt_pending_cmd *cmd;
6030 u16 eir_len;
6031 int err;
6032
6033 BT_DBG("%s status %u", hdev->name, status);
6034
6035 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6036 if (!cmd)
6037 return;
6038
6039 mgmt_cp = cmd->param;
6040
6041 if (status) {
6042 status = mgmt_status(status);
6043 eir_len = 0;
6044
6045 h192 = NULL;
6046 r192 = NULL;
6047 h256 = NULL;
6048 r256 = NULL;
6049 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6050 struct hci_rp_read_local_oob_data *rp;
6051
6052 if (skb->len != sizeof(*rp)) {
6053 status = MGMT_STATUS_FAILED;
6054 eir_len = 0;
6055 } else {
6056 status = MGMT_STATUS_SUCCESS;
6057 rp = (void *)skb->data;
6058
6059 eir_len = 5 + 18 + 18;
6060 h192 = rp->hash;
6061 r192 = rp->rand;
6062 h256 = NULL;
6063 r256 = NULL;
6064 }
6065 } else {
6066 struct hci_rp_read_local_oob_ext_data *rp;
6067
6068 if (skb->len != sizeof(*rp)) {
6069 status = MGMT_STATUS_FAILED;
6070 eir_len = 0;
6071 } else {
6072 status = MGMT_STATUS_SUCCESS;
6073 rp = (void *)skb->data;
6074
6075 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6076 eir_len = 5 + 18 + 18;
6077 h192 = NULL;
6078 r192 = NULL;
6079 } else {
6080 eir_len = 5 + 18 + 18 + 18 + 18;
6081 h192 = rp->hash192;
6082 r192 = rp->rand192;
6083 }
6084
6085 h256 = rp->hash256;
6086 r256 = rp->rand256;
6087 }
6088 }
6089
6090 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6091 if (!mgmt_rp)
6092 goto done;
6093
6094 if (status)
6095 goto send_rsp;
6096
6097 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6098 hdev->dev_class, 3);
6099
6100 if (h192 && r192) {
6101 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6102 EIR_SSP_HASH_C192, h192, 16);
6103 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6104 EIR_SSP_RAND_R192, r192, 16);
6105 }
6106
6107 if (h256 && r256) {
6108 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6109 EIR_SSP_HASH_C256, h256, 16);
6110 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6111 EIR_SSP_RAND_R256, r256, 16);
6112 }
6113
6114send_rsp:
6115 mgmt_rp->type = mgmt_cp->type;
6116 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6117
6118 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6119 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6120 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6121 if (err < 0 || status)
6122 goto done;
6123
6124 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6125
6126 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6127 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6128 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6129done:
6130 kfree(mgmt_rp);
6131 mgmt_pending_remove(cmd);
6132}
6133
6134static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6135 struct mgmt_cp_read_local_oob_ext_data *cp)
6136{
6137 struct mgmt_pending_cmd *cmd;
6138 struct hci_request req;
6139 int err;
6140
6141 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6142 cp, sizeof(*cp));
6143 if (!cmd)
6144 return -ENOMEM;
6145
6146 hci_req_init(&req, hdev);
6147
6148 if (bredr_sc_enabled(hdev))
6149 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6150 else
6151 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6152
6153 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6154 if (err < 0) {
6155 mgmt_pending_remove(cmd);
6156 return err;
6157 }
6158
6159 return 0;
6160}
6161
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006162static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6163 void *data, u16 data_len)
6164{
6165 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6166 struct mgmt_rp_read_local_oob_ext_data *rp;
6167 size_t rp_len;
6168 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006169 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006170 int err;
6171
6172 BT_DBG("%s", hdev->name);
6173
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006174 if (hdev_is_powered(hdev)) {
6175 switch (cp->type) {
6176 case BIT(BDADDR_BREDR):
6177 status = mgmt_bredr_support(hdev);
6178 if (status)
6179 eir_len = 0;
6180 else
6181 eir_len = 5;
6182 break;
6183 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6184 status = mgmt_le_support(hdev);
6185 if (status)
6186 eir_len = 0;
6187 else
6188 eir_len = 9 + 3 + 18 + 18 + 3;
6189 break;
6190 default:
6191 status = MGMT_STATUS_INVALID_PARAMS;
6192 eir_len = 0;
6193 break;
6194 }
6195 } else {
6196 status = MGMT_STATUS_NOT_POWERED;
6197 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006198 }
6199
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006200 rp_len = sizeof(*rp) + eir_len;
6201 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006202 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006203 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006204
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006205 if (status)
6206 goto complete;
6207
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006208 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006209
6210 eir_len = 0;
6211 switch (cp->type) {
6212 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006213 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6214 err = read_local_ssp_oob_req(hdev, sk, cp);
6215 hci_dev_unlock(hdev);
6216 if (!err)
6217 goto done;
6218
6219 status = MGMT_STATUS_FAILED;
6220 goto complete;
6221 } else {
6222 eir_len = eir_append_data(rp->eir, eir_len,
6223 EIR_CLASS_OF_DEV,
6224 hdev->dev_class, 3);
6225 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006226 break;
6227 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006228 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6229 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006230 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006231 status = MGMT_STATUS_FAILED;
6232 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006233 }
6234
Marcel Holtmanne2135682015-04-02 12:00:58 -07006235 /* This should return the active RPA, but since the RPA
6236 * is only programmed on demand, it is really hard to fill
6237 * this in at the moment. For now disallow retrieving
6238 * local out-of-band data when privacy is in use.
6239 *
6240 * Returning the identity address will not help here since
6241 * pairing happens before the identity resolving key is
6242 * known and thus the connection establishment happens
6243 * based on the RPA and not the identity address.
6244 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006245 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006246 hci_dev_unlock(hdev);
6247 status = MGMT_STATUS_REJECTED;
6248 goto complete;
6249 }
6250
6251 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6252 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6253 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6254 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006255 memcpy(addr, &hdev->static_addr, 6);
6256 addr[6] = 0x01;
6257 } else {
6258 memcpy(addr, &hdev->bdaddr, 6);
6259 addr[6] = 0x00;
6260 }
6261
6262 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6263 addr, sizeof(addr));
6264
6265 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6266 role = 0x02;
6267 else
6268 role = 0x01;
6269
6270 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6271 &role, sizeof(role));
6272
Marcel Holtmann5082a592015-03-16 12:39:00 -07006273 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6274 eir_len = eir_append_data(rp->eir, eir_len,
6275 EIR_LE_SC_CONFIRM,
6276 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006277
Marcel Holtmann5082a592015-03-16 12:39:00 -07006278 eir_len = eir_append_data(rp->eir, eir_len,
6279 EIR_LE_SC_RANDOM,
6280 rand, sizeof(rand));
6281 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006282
Johan Hedbergf2252572015-11-18 12:49:20 +02006283 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006284
6285 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6286 flags |= LE_AD_NO_BREDR;
6287
6288 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6289 &flags, sizeof(flags));
6290 break;
6291 }
6292
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006293 hci_dev_unlock(hdev);
6294
Marcel Holtmann72000df2015-03-16 16:11:21 -07006295 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6296
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006297 status = MGMT_STATUS_SUCCESS;
6298
6299complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006300 rp->type = cp->type;
6301 rp->eir_len = cpu_to_le16(eir_len);
6302
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006303 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006304 status, rp, sizeof(*rp) + eir_len);
6305 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006306 goto done;
6307
6308 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6309 rp, sizeof(*rp) + eir_len,
6310 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006311
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006312done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006313 kfree(rp);
6314
6315 return err;
6316}
6317
Arman Uguray089fa8c2015-03-25 18:53:45 -07006318static u32 get_supported_adv_flags(struct hci_dev *hdev)
6319{
6320 u32 flags = 0;
6321
6322 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6323 flags |= MGMT_ADV_FLAG_DISCOV;
6324 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6325 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006326 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006327 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006328
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306329 /* In extended adv TX_POWER returned from Set Adv Param
6330 * will be always valid.
6331 */
6332 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6333 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006334 flags |= MGMT_ADV_FLAG_TX_POWER;
6335
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306336 if (ext_adv_capable(hdev)) {
6337 flags |= MGMT_ADV_FLAG_SEC_1M;
6338
6339 if (hdev->le_features[1] & HCI_LE_PHY_2M)
6340 flags |= MGMT_ADV_FLAG_SEC_2M;
6341
6342 if (hdev->le_features[1] & HCI_LE_PHY_CODED)
6343 flags |= MGMT_ADV_FLAG_SEC_CODED;
6344 }
6345
Arman Uguray089fa8c2015-03-25 18:53:45 -07006346 return flags;
6347}
6348
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006349static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6350 void *data, u16 data_len)
6351{
6352 struct mgmt_rp_read_adv_features *rp;
6353 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02006354 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006355 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006356 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02006357 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006358
6359 BT_DBG("%s", hdev->name);
6360
Arman Uguray089fa8c2015-03-25 18:53:45 -07006361 if (!lmp_le_capable(hdev))
6362 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6363 MGMT_STATUS_REJECTED);
6364
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006365 hci_dev_lock(hdev);
6366
Johan Hedberg02c04af2015-11-26 12:15:58 +02006367 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006368 rp = kmalloc(rp_len, GFP_ATOMIC);
6369 if (!rp) {
6370 hci_dev_unlock(hdev);
6371 return -ENOMEM;
6372 }
6373
Arman Uguray089fa8c2015-03-25 18:53:45 -07006374 supported_flags = get_supported_adv_flags(hdev);
6375
6376 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006377 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6378 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006379 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02006380 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006381
Johan Hedberg02c04af2015-11-26 12:15:58 +02006382 instance = rp->instance;
6383 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6384 *instance = adv_instance->instance;
6385 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006386 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006387
6388 hci_dev_unlock(hdev);
6389
6390 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6391 MGMT_STATUS_SUCCESS, rp, rp_len);
6392
6393 kfree(rp);
6394
6395 return err;
6396}
6397
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006398static u8 calculate_name_len(struct hci_dev *hdev)
6399{
6400 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6401
6402 return append_local_name(hdev, buf, 0);
6403}
6404
6405static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6406 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006407{
Arman Uguray4117ed72015-03-23 15:57:14 -07006408 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006409
Marcel Holtmann31a32482015-11-19 16:16:42 +01006410 if (is_adv_data) {
6411 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6412 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006413 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006414 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006415
Szymon Janc2bb368702016-09-18 12:50:05 +02006416 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006417 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006418 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006419 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006420 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006421
Szymon Janc2bb368702016-09-18 12:50:05 +02006422 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006423 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006424 }
6425
Szymon Janc2bb368702016-09-18 12:50:05 +02006426 return max_len;
6427}
6428
6429static bool flags_managed(u32 adv_flags)
6430{
6431 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6432 MGMT_ADV_FLAG_LIMITED_DISCOV |
6433 MGMT_ADV_FLAG_MANAGED_FLAGS);
6434}
6435
6436static bool tx_power_managed(u32 adv_flags)
6437{
6438 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6439}
6440
6441static bool name_managed(u32 adv_flags)
6442{
6443 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6444}
6445
6446static bool appearance_managed(u32 adv_flags)
6447{
6448 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6449}
6450
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006451static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6452 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006453{
6454 int i, cur_len;
6455 u8 max_len;
6456
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006457 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02006458
Arman Uguray4117ed72015-03-23 15:57:14 -07006459 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006460 return false;
6461
Arman Uguray4117ed72015-03-23 15:57:14 -07006462 /* Make sure that the data is correctly formatted. */
6463 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6464 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006465
Szymon Janc9c9db782016-09-18 12:50:06 +02006466 if (data[i + 1] == EIR_FLAGS &&
6467 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006468 return false;
6469
Szymon Janc2bb368702016-09-18 12:50:05 +02006470 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6471 return false;
6472
6473 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6474 return false;
6475
6476 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6477 return false;
6478
6479 if (data[i + 1] == EIR_APPEARANCE &&
6480 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006481 return false;
6482
Arman Uguray24b4f382015-03-23 15:57:12 -07006483 /* If the current field length would exceed the total data
6484 * length, then it's invalid.
6485 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006486 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006487 return false;
6488 }
6489
6490 return true;
6491}
6492
Arman Uguray24b4f382015-03-23 15:57:12 -07006493static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6494 u16 opcode)
6495{
6496 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006497 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006498 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006499 struct adv_info *adv_instance, *n;
6500 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006501
6502 BT_DBG("status %d", status);
6503
6504 hci_dev_lock(hdev);
6505
6506 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6507
Florian Grandelfffd38b2015-06-18 03:16:47 +02006508 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6509 if (!adv_instance->pending)
6510 continue;
6511
6512 if (!status) {
6513 adv_instance->pending = false;
6514 continue;
6515 }
6516
6517 instance = adv_instance->instance;
6518
6519 if (hdev->cur_adv_instance == instance)
6520 cancel_adv_timeout(hdev);
6521
6522 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006523 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006524 }
6525
6526 if (!cmd)
6527 goto unlock;
6528
Florian Grandelfffd38b2015-06-18 03:16:47 +02006529 cp = cmd->param;
6530 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006531
6532 if (status)
6533 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6534 mgmt_status(status));
6535 else
6536 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6537 mgmt_status(status), &rp, sizeof(rp));
6538
6539 mgmt_pending_remove(cmd);
6540
6541unlock:
6542 hci_dev_unlock(hdev);
6543}
6544
6545static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6546 void *data, u16 data_len)
6547{
6548 struct mgmt_cp_add_advertising *cp = data;
6549 struct mgmt_rp_add_advertising rp;
6550 u32 flags;
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306551 u32 supported_flags, phy_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006552 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006553 u16 timeout, duration;
6554 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6555 u8 schedule_instance = 0;
6556 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006557 int err;
6558 struct mgmt_pending_cmd *cmd;
6559 struct hci_request req;
6560
6561 BT_DBG("%s", hdev->name);
6562
6563 status = mgmt_le_support(hdev);
6564 if (status)
6565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6566 status);
6567
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006568 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6569 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6570 MGMT_STATUS_INVALID_PARAMS);
6571
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006572 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6573 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6574 MGMT_STATUS_INVALID_PARAMS);
6575
Arman Uguray24b4f382015-03-23 15:57:12 -07006576 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006577 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006578 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006579
Florian Grandelfffd38b2015-06-18 03:16:47 +02006580 /* The current implementation only supports a subset of the specified
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306581 * flags. Also need to check mutual exclusiveness of sec flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006582 */
6583 supported_flags = get_supported_adv_flags(hdev);
Jaganath Kanakkassery85a721a2018-07-19 17:09:47 +05306584 phy_flags = flags & MGMT_ADV_FLAG_SEC_MASK;
6585 if (flags & ~supported_flags ||
6586 ((phy_flags && (phy_flags ^ (phy_flags & -phy_flags)))))
Arman Uguray24b4f382015-03-23 15:57:12 -07006587 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6588 MGMT_STATUS_INVALID_PARAMS);
6589
6590 hci_dev_lock(hdev);
6591
Arman Uguray912098a2015-03-23 15:57:15 -07006592 if (timeout && !hdev_is_powered(hdev)) {
6593 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6594 MGMT_STATUS_REJECTED);
6595 goto unlock;
6596 }
6597
Arman Uguray24b4f382015-03-23 15:57:12 -07006598 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006599 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006600 pending_find(MGMT_OP_SET_LE, hdev)) {
6601 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6602 MGMT_STATUS_BUSY);
6603 goto unlock;
6604 }
6605
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006606 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
6607 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006608 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006609 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6610 MGMT_STATUS_INVALID_PARAMS);
6611 goto unlock;
6612 }
6613
Florian Grandelfffd38b2015-06-18 03:16:47 +02006614 err = hci_add_adv_instance(hdev, cp->instance, flags,
6615 cp->adv_data_len, cp->data,
6616 cp->scan_rsp_len,
6617 cp->data + cp->adv_data_len,
6618 timeout, duration);
6619 if (err < 0) {
6620 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6621 MGMT_STATUS_FAILED);
6622 goto unlock;
6623 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006624
Florian Grandelfffd38b2015-06-18 03:16:47 +02006625 /* Only trigger an advertising added event if a new instance was
6626 * actually added.
6627 */
6628 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006629 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006630
Florian Grandelfffd38b2015-06-18 03:16:47 +02006631 if (hdev->cur_adv_instance == cp->instance) {
6632 /* If the currently advertised instance is being changed then
6633 * cancel the current advertising and schedule the next
6634 * instance. If there is only one instance then the overridden
6635 * advertising data will be visible right away.
6636 */
6637 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006638
Florian Grandelfffd38b2015-06-18 03:16:47 +02006639 next_instance = hci_get_next_instance(hdev, cp->instance);
6640 if (next_instance)
6641 schedule_instance = next_instance->instance;
6642 } else if (!hdev->adv_instance_timeout) {
6643 /* Immediately advertise the new instance if no other
6644 * instance is currently being advertised.
6645 */
6646 schedule_instance = cp->instance;
6647 }
Arman Uguray912098a2015-03-23 15:57:15 -07006648
Florian Grandelfffd38b2015-06-18 03:16:47 +02006649 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6650 * there is no instance to be advertised then we have no HCI
6651 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006652 */
6653 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006654 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6655 !schedule_instance) {
6656 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006657 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6658 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6659 goto unlock;
6660 }
6661
6662 /* We're good to go, update advertising data, parameters, and start
6663 * advertising.
6664 */
6665 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6666 data_len);
6667 if (!cmd) {
6668 err = -ENOMEM;
6669 goto unlock;
6670 }
6671
6672 hci_req_init(&req, hdev);
6673
Johan Hedbergf2252572015-11-18 12:49:20 +02006674 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006675
Florian Grandelfffd38b2015-06-18 03:16:47 +02006676 if (!err)
6677 err = hci_req_run(&req, add_advertising_complete);
6678
Arman Uguray24b4f382015-03-23 15:57:12 -07006679 if (err < 0)
6680 mgmt_pending_remove(cmd);
6681
6682unlock:
6683 hci_dev_unlock(hdev);
6684
6685 return err;
6686}
6687
Arman Ugurayda9293352015-03-23 15:57:13 -07006688static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6689 u16 opcode)
6690{
6691 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006692 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006693 struct mgmt_rp_remove_advertising rp;
6694
6695 BT_DBG("status %d", status);
6696
6697 hci_dev_lock(hdev);
6698
6699 /* A failure status here only means that we failed to disable
6700 * advertising. Otherwise, the advertising instance has been removed,
6701 * so report success.
6702 */
6703 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6704 if (!cmd)
6705 goto unlock;
6706
Florian Grandel01948332015-06-18 03:16:48 +02006707 cp = cmd->param;
6708 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006709
6710 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6711 &rp, sizeof(rp));
6712 mgmt_pending_remove(cmd);
6713
6714unlock:
6715 hci_dev_unlock(hdev);
6716}
6717
6718static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6719 void *data, u16 data_len)
6720{
6721 struct mgmt_cp_remove_advertising *cp = data;
6722 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006723 struct mgmt_pending_cmd *cmd;
6724 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006725 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006726
6727 BT_DBG("%s", hdev->name);
6728
Arman Ugurayda9293352015-03-23 15:57:13 -07006729 hci_dev_lock(hdev);
6730
Johan Hedberg952497b2015-06-18 21:05:31 +03006731 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006732 err = mgmt_cmd_status(sk, hdev->id,
6733 MGMT_OP_REMOVE_ADVERTISING,
6734 MGMT_STATUS_INVALID_PARAMS);
6735 goto unlock;
6736 }
6737
Arman Ugurayda9293352015-03-23 15:57:13 -07006738 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6739 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6740 pending_find(MGMT_OP_SET_LE, hdev)) {
6741 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6742 MGMT_STATUS_BUSY);
6743 goto unlock;
6744 }
6745
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006746 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006747 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6748 MGMT_STATUS_INVALID_PARAMS);
6749 goto unlock;
6750 }
6751
Florian Grandel01948332015-06-18 03:16:48 +02006752 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006753
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006754 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006755
Florian Grandel01948332015-06-18 03:16:48 +02006756 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006757 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006758
Florian Grandel01948332015-06-18 03:16:48 +02006759 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6760 * flag is set or the device isn't powered then we have no HCI
6761 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006762 */
Florian Grandel01948332015-06-18 03:16:48 +02006763 if (skb_queue_empty(&req.cmd_q) ||
6764 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006765 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05306766 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02006767 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006768 err = mgmt_cmd_complete(sk, hdev->id,
6769 MGMT_OP_REMOVE_ADVERTISING,
6770 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6771 goto unlock;
6772 }
6773
6774 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6775 data_len);
6776 if (!cmd) {
6777 err = -ENOMEM;
6778 goto unlock;
6779 }
6780
Arman Ugurayda9293352015-03-23 15:57:13 -07006781 err = hci_req_run(&req, remove_advertising_complete);
6782 if (err < 0)
6783 mgmt_pending_remove(cmd);
6784
6785unlock:
6786 hci_dev_unlock(hdev);
6787
6788 return err;
6789}
6790
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006791static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6792 void *data, u16 data_len)
6793{
6794 struct mgmt_cp_get_adv_size_info *cp = data;
6795 struct mgmt_rp_get_adv_size_info rp;
6796 u32 flags, supported_flags;
6797 int err;
6798
6799 BT_DBG("%s", hdev->name);
6800
6801 if (!lmp_le_capable(hdev))
6802 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6803 MGMT_STATUS_REJECTED);
6804
6805 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6806 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6807 MGMT_STATUS_INVALID_PARAMS);
6808
6809 flags = __le32_to_cpu(cp->flags);
6810
6811 /* The current implementation only supports a subset of the specified
6812 * flags.
6813 */
6814 supported_flags = get_supported_adv_flags(hdev);
6815 if (flags & ~supported_flags)
6816 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6817 MGMT_STATUS_INVALID_PARAMS);
6818
6819 rp.instance = cp->instance;
6820 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006821 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
6822 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006823
6824 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6825 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6826
6827 return err;
6828}
6829
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006830static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006831 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006832 { read_version, MGMT_READ_VERSION_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_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006836 HCI_MGMT_NO_HDEV |
6837 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006838 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006839 HCI_MGMT_NO_HDEV |
6840 HCI_MGMT_UNTRUSTED },
6841 { read_controller_info, MGMT_READ_INFO_SIZE,
6842 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006843 { set_powered, MGMT_SETTING_SIZE },
6844 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6845 { set_connectable, MGMT_SETTING_SIZE },
6846 { set_fast_connectable, MGMT_SETTING_SIZE },
6847 { set_bondable, MGMT_SETTING_SIZE },
6848 { set_link_security, MGMT_SETTING_SIZE },
6849 { set_ssp, MGMT_SETTING_SIZE },
6850 { set_hs, MGMT_SETTING_SIZE },
6851 { set_le, MGMT_SETTING_SIZE },
6852 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6853 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6854 { add_uuid, MGMT_ADD_UUID_SIZE },
6855 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006856 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6857 HCI_MGMT_VAR_LEN },
6858 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6859 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006860 { disconnect, MGMT_DISCONNECT_SIZE },
6861 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6862 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6863 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6864 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6865 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6866 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6867 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6868 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6869 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6870 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6871 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006872 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6873 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6874 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006875 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6876 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6877 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6878 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6879 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6880 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6881 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6882 { set_advertising, MGMT_SETTING_SIZE },
6883 { set_bredr, MGMT_SETTING_SIZE },
6884 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6885 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6886 { set_secure_conn, MGMT_SETTING_SIZE },
6887 { set_debug_keys, MGMT_SETTING_SIZE },
6888 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006889 { load_irks, MGMT_LOAD_IRKS_SIZE,
6890 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006891 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6892 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6893 { add_device, MGMT_ADD_DEVICE_SIZE },
6894 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006895 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6896 HCI_MGMT_VAR_LEN },
6897 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006898 HCI_MGMT_NO_HDEV |
6899 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006900 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006901 HCI_MGMT_UNCONFIGURED |
6902 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006903 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6904 HCI_MGMT_UNCONFIGURED },
6905 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6906 HCI_MGMT_UNCONFIGURED },
6907 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6908 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006909 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006910 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006911 HCI_MGMT_NO_HDEV |
6912 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006913 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006914 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6915 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006916 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006917 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006918 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006919 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6920 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006921 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05306922 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05306923 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006924};
6925
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006926void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006927{
Marcel Holtmannced85542015-03-14 19:27:56 -07006928 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006929
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006930 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6931 return;
6932
Marcel Holtmannf9207332015-03-14 19:27:55 -07006933 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006934 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006935 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6936 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6937 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006938 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006939 } else {
6940 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6941 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006942 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006943 }
6944 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006945 case HCI_AMP:
6946 ev.type = 0x02;
6947 break;
6948 default:
6949 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006950 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006951
6952 ev.bus = hdev->bus;
6953
6954 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6955 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006956}
6957
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006958void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006959{
Marcel Holtmannced85542015-03-14 19:27:56 -07006960 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006961 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006962
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006963 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6964 return;
6965
Marcel Holtmannf9207332015-03-14 19:27:55 -07006966 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006967 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006968 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006969
Marcel Holtmannf9207332015-03-14 19:27:55 -07006970 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6971 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6972 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006973 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006974 } else {
6975 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6976 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006977 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006978 }
6979 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006980 case HCI_AMP:
6981 ev.type = 0x02;
6982 break;
6983 default:
6984 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006985 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006986
6987 ev.bus = hdev->bus;
6988
6989 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6990 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006991}
6992
Andre Guedes6046dc32014-02-26 20:21:51 -03006993/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006994static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006995{
6996 struct hci_conn_params *p;
6997
6998 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006999 /* Needed for AUTO_OFF case where might not "really"
7000 * have been powered off.
7001 */
7002 list_del_init(&p->action);
7003
7004 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007005 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007006 case HCI_AUTO_CONN_ALWAYS:
7007 list_add(&p->action, &hdev->pend_le_conns);
7008 break;
7009 case HCI_AUTO_CONN_REPORT:
7010 list_add(&p->action, &hdev->pend_le_reports);
7011 break;
7012 default:
7013 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007014 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007015 }
7016}
7017
Johan Hedberg2ff13892015-11-25 16:15:44 +02007018void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007019{
7020 struct cmd_lookup match = { NULL, hdev };
7021
Johan Hedberg2ff13892015-11-25 16:15:44 +02007022 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007023
Johan Hedberg2ff13892015-11-25 16:15:44 +02007024 hci_dev_lock(hdev);
7025
7026 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007027 restart_le_actions(hdev);
7028 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007029 }
7030
Johan Hedberg229ab392013-03-15 17:06:53 -05007031 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7032
7033 new_settings(hdev, match.sk);
7034
Johan Hedberg229ab392013-03-15 17:06:53 -05007035 if (match.sk)
7036 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007037
7038 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007039}
7040
Johan Hedberg2ff13892015-11-25 16:15:44 +02007041void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007042{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007043 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007044 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007045
Johan Hedberg229ab392013-03-15 17:06:53 -05007046 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007047
7048 /* If the power off is because of hdev unregistration let
7049 * use the appropriate INVALID_INDEX status. Otherwise use
7050 * NOT_POWERED. We cover both scenarios here since later in
7051 * mgmt_index_removed() any hci_conn callbacks will have already
7052 * been triggered, potentially causing misleading DISCONNECTED
7053 * status responses.
7054 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007055 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007056 status = MGMT_STATUS_INVALID_INDEX;
7057 else
7058 status = MGMT_STATUS_NOT_POWERED;
7059
7060 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007061
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007062 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007063 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7064 zero_cod, sizeof(zero_cod),
7065 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007066 ext_info_changed(hdev, NULL);
7067 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007068
Johan Hedberg2ff13892015-11-25 16:15:44 +02007069 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007070
7071 if (match.sk)
7072 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007073}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007074
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007075void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007076{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007077 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007078 u8 status;
7079
Johan Hedberg333ae952015-03-17 13:48:47 +02007080 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007081 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007082 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007083
7084 if (err == -ERFKILL)
7085 status = MGMT_STATUS_RFKILLED;
7086 else
7087 status = MGMT_STATUS_FAILED;
7088
Johan Hedberga69e8372015-03-06 21:08:53 +02007089 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007090
7091 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007092}
7093
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007094void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7095 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007096{
Johan Hedberg86742e12011-11-07 23:13:38 +02007097 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007098
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007099 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007100
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007101 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007102 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007103 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007104 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007105 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007106 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007107
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007108 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007109}
Johan Hedbergf7520542011-01-20 12:34:39 +02007110
Johan Hedbergd7b25452014-05-23 13:19:53 +03007111static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7112{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007113 switch (ltk->type) {
7114 case SMP_LTK:
7115 case SMP_LTK_SLAVE:
7116 if (ltk->authenticated)
7117 return MGMT_LTK_AUTHENTICATED;
7118 return MGMT_LTK_UNAUTHENTICATED;
7119 case SMP_LTK_P256:
7120 if (ltk->authenticated)
7121 return MGMT_LTK_P256_AUTH;
7122 return MGMT_LTK_P256_UNAUTH;
7123 case SMP_LTK_P256_DEBUG:
7124 return MGMT_LTK_P256_DEBUG;
7125 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007126
7127 return MGMT_LTK_UNAUTHENTICATED;
7128}
7129
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007130void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007131{
7132 struct mgmt_ev_new_long_term_key ev;
7133
7134 memset(&ev, 0, sizeof(ev));
7135
Marcel Holtmann5192d302014-02-19 17:11:58 -08007136 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007137 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007138 * to store long term keys. Their addresses will change the
7139 * next time around.
7140 *
7141 * Only when a remote device provides an identity address
7142 * make sure the long term key is stored. If the remote
7143 * identity is known, the long term keys are internally
7144 * mapped to the identity address. So allow static random
7145 * and public addresses here.
7146 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007147 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7148 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7149 ev.store_hint = 0x00;
7150 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007151 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007152
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007153 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007154 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007155 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007156 ev.key.enc_size = key->enc_size;
7157 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007158 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007159
Johan Hedberg2ceba532014-06-16 19:25:16 +03007160 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007161 ev.key.master = 1;
7162
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007163 /* Make sure we copy only the significant bytes based on the
7164 * encryption key size, and set the rest of the value to zeroes.
7165 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007166 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007167 memset(ev.key.val + key->enc_size, 0,
7168 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007169
Marcel Holtmann083368f2013-10-15 14:26:29 -07007170 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007171}
7172
Johan Hedbergcad20c22015-10-12 13:36:19 +02007173void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007174{
7175 struct mgmt_ev_new_irk ev;
7176
7177 memset(&ev, 0, sizeof(ev));
7178
Johan Hedbergcad20c22015-10-12 13:36:19 +02007179 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007180
Johan Hedberg95fbac82014-02-19 15:18:31 +02007181 bacpy(&ev.rpa, &irk->rpa);
7182 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7183 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7184 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7185
7186 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7187}
7188
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007189void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7190 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007191{
7192 struct mgmt_ev_new_csrk ev;
7193
7194 memset(&ev, 0, sizeof(ev));
7195
7196 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007197 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007198 * to store signature resolving keys. Their addresses will change
7199 * the next time around.
7200 *
7201 * Only when a remote device provides an identity address
7202 * make sure the signature resolving key is stored. So allow
7203 * static random and public addresses here.
7204 */
7205 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7206 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7207 ev.store_hint = 0x00;
7208 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007209 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007210
7211 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7212 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007213 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007214 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7215
7216 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7217}
7218
Andre Guedesffb5a8272014-07-01 18:10:11 -03007219void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007220 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7221 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007222{
7223 struct mgmt_ev_new_conn_param ev;
7224
Johan Hedbergc103aea2014-07-02 17:37:34 +03007225 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7226 return;
7227
Andre Guedesffb5a8272014-07-01 18:10:11 -03007228 memset(&ev, 0, sizeof(ev));
7229 bacpy(&ev.addr.bdaddr, bdaddr);
7230 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007231 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007232 ev.min_interval = cpu_to_le16(min_interval);
7233 ev.max_interval = cpu_to_le16(max_interval);
7234 ev.latency = cpu_to_le16(latency);
7235 ev.timeout = cpu_to_le16(timeout);
7236
7237 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7238}
7239
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007240void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7241 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007242{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007243 char buf[512];
7244 struct mgmt_ev_device_connected *ev = (void *) buf;
7245 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007246
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007247 bacpy(&ev->addr.bdaddr, &conn->dst);
7248 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007249
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007250 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007251
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007252 /* We must ensure that the EIR Data fields are ordered and
7253 * unique. Keep it simple for now and avoid the problem by not
7254 * adding any BR/EDR data to the LE adv.
7255 */
7256 if (conn->le_adv_data_len > 0) {
7257 memcpy(&ev->eir[eir_len],
7258 conn->le_adv_data, conn->le_adv_data_len);
7259 eir_len = conn->le_adv_data_len;
7260 } else {
7261 if (name_len > 0)
7262 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7263 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007264
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007265 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007266 eir_len = eir_append_data(ev->eir, eir_len,
7267 EIR_CLASS_OF_DEV,
7268 conn->dev_class, 3);
7269 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007270
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007271 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007272
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007273 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7274 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007275}
7276
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007277static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007278{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007279 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007280
Johan Hedbergf5818c22014-12-05 13:36:02 +02007281 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007282
7283 *sk = cmd->sk;
7284 sock_hold(*sk);
7285
Johan Hedberga664b5b2011-02-19 12:06:02 -03007286 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007287}
7288
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007289static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007290{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007291 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007292 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007293
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007294 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7295
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007296 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007297 mgmt_pending_remove(cmd);
7298}
7299
Johan Hedberg84c61d92014-08-01 11:13:30 +03007300bool mgmt_powering_down(struct hci_dev *hdev)
7301{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007302 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007303 struct mgmt_mode *cp;
7304
Johan Hedberg333ae952015-03-17 13:48:47 +02007305 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007306 if (!cmd)
7307 return false;
7308
7309 cp = cmd->param;
7310 if (!cp->val)
7311 return true;
7312
7313 return false;
7314}
7315
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007316void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007317 u8 link_type, u8 addr_type, u8 reason,
7318 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007319{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007320 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007321 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007322
Johan Hedberg84c61d92014-08-01 11:13:30 +03007323 /* The connection is still in hci_conn_hash so test for 1
7324 * instead of 0 to know if this is the last one.
7325 */
7326 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7327 cancel_delayed_work(&hdev->power_off);
7328 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007329 }
7330
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007331 if (!mgmt_connected)
7332 return;
7333
Andre Guedes57eb7762013-10-30 19:01:41 -03007334 if (link_type != ACL_LINK && link_type != LE_LINK)
7335 return;
7336
Johan Hedberg744cf192011-11-08 20:40:14 +02007337 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007338
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007339 bacpy(&ev.addr.bdaddr, bdaddr);
7340 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7341 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007342
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007343 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007344
7345 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007346 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007347
Johan Hedberg124f6e32012-02-09 13:50:12 +02007348 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007349 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007350}
7351
Marcel Holtmann78929242013-10-06 23:55:47 -07007352void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7353 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007354{
Andre Guedes3655bba2013-10-30 19:01:40 -03007355 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7356 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007357 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007358
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007359 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7360 hdev);
7361
Johan Hedberg333ae952015-03-17 13:48:47 +02007362 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007363 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007364 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007365
Andre Guedes3655bba2013-10-30 19:01:40 -03007366 cp = cmd->param;
7367
7368 if (bacmp(bdaddr, &cp->addr.bdaddr))
7369 return;
7370
7371 if (cp->addr.type != bdaddr_type)
7372 return;
7373
Johan Hedbergf5818c22014-12-05 13:36:02 +02007374 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007375 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007376}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007377
Marcel Holtmann445608d2013-10-06 23:55:48 -07007378void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7379 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007380{
7381 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007382
Johan Hedberg84c61d92014-08-01 11:13:30 +03007383 /* The connection is still in hci_conn_hash so test for 1
7384 * instead of 0 to know if this is the last one.
7385 */
7386 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7387 cancel_delayed_work(&hdev->power_off);
7388 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007389 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007390
Johan Hedberg4c659c32011-11-07 23:13:39 +02007391 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007392 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007393 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007394
Marcel Holtmann445608d2013-10-06 23:55:48 -07007395 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007396}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007397
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007398void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007399{
7400 struct mgmt_ev_pin_code_request ev;
7401
Johan Hedbergd8457692012-02-17 14:24:57 +02007402 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007403 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007404 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007405
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007406 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007407}
7408
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007409void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7410 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007411{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007412 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007413
Johan Hedberg333ae952015-03-17 13:48:47 +02007414 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007415 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007416 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007417
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007418 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007419 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007420}
7421
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007422void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7423 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007424{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007425 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007426
Johan Hedberg333ae952015-03-17 13:48:47 +02007427 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007428 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007429 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007430
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007431 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007432 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007433}
Johan Hedberga5c29682011-02-19 12:05:57 -03007434
Johan Hedberg744cf192011-11-08 20:40:14 +02007435int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007436 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007437 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007438{
7439 struct mgmt_ev_user_confirm_request ev;
7440
Johan Hedberg744cf192011-11-08 20:40:14 +02007441 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007442
Johan Hedberg272d90d2012-02-09 15:26:12 +02007443 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007444 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007445 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007446 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007447
Johan Hedberg744cf192011-11-08 20:40:14 +02007448 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007449 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007450}
7451
Johan Hedberg272d90d2012-02-09 15:26:12 +02007452int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007453 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007454{
7455 struct mgmt_ev_user_passkey_request ev;
7456
7457 BT_DBG("%s", hdev->name);
7458
Johan Hedberg272d90d2012-02-09 15:26:12 +02007459 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007460 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007461
7462 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007463 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007464}
7465
Brian Gix0df4c182011-11-16 13:53:13 -08007466static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007467 u8 link_type, u8 addr_type, u8 status,
7468 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007469{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007470 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007471
Johan Hedberg333ae952015-03-17 13:48:47 +02007472 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007473 if (!cmd)
7474 return -ENOENT;
7475
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007476 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007477 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007478
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007479 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007480}
7481
Johan Hedberg744cf192011-11-08 20:40:14 +02007482int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007483 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007484{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007485 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007486 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007487}
7488
Johan Hedberg272d90d2012-02-09 15:26:12 +02007489int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007490 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007491{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007492 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007493 status,
7494 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007495}
Johan Hedberg2a611692011-02-19 12:06:00 -03007496
Brian Gix604086b2011-11-23 08:28:33 -08007497int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007498 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007499{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007500 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007501 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007502}
7503
Johan Hedberg272d90d2012-02-09 15:26:12 +02007504int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007505 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007506{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007507 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007508 status,
7509 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007510}
7511
Johan Hedberg92a25252012-09-06 18:39:26 +03007512int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7513 u8 link_type, u8 addr_type, u32 passkey,
7514 u8 entered)
7515{
7516 struct mgmt_ev_passkey_notify ev;
7517
7518 BT_DBG("%s", hdev->name);
7519
7520 bacpy(&ev.addr.bdaddr, bdaddr);
7521 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7522 ev.passkey = __cpu_to_le32(passkey);
7523 ev.entered = entered;
7524
7525 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7526}
7527
Johan Hedberge1e930f2014-09-08 17:09:49 -07007528void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007529{
7530 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007531 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007532 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007533
Johan Hedberge1e930f2014-09-08 17:09:49 -07007534 bacpy(&ev.addr.bdaddr, &conn->dst);
7535 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7536 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007537
Johan Hedberge1e930f2014-09-08 17:09:49 -07007538 cmd = find_pairing(conn);
7539
7540 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7541 cmd ? cmd->sk : NULL);
7542
Johan Hedberga511b352014-12-11 21:45:45 +02007543 if (cmd) {
7544 cmd->cmd_complete(cmd, status);
7545 mgmt_pending_remove(cmd);
7546 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007547}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007548
Marcel Holtmann464996a2013-10-15 14:26:24 -07007549void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007550{
7551 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007552 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007553
7554 if (status) {
7555 u8 mgmt_err = mgmt_status(status);
7556 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007557 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007558 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007559 }
7560
Marcel Holtmann464996a2013-10-15 14:26:24 -07007561 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007562 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007563 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007564 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007565
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007566 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007567 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007568
Johan Hedberg47990ea2012-02-22 11:58:37 +02007569 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007570 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007571
7572 if (match.sk)
7573 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007574}
7575
Johan Hedberg890ea892013-03-15 17:06:52 -05007576static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007577{
Johan Hedberg890ea892013-03-15 17:06:52 -05007578 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007579 struct hci_cp_write_eir cp;
7580
Johan Hedberg976eb202012-10-24 21:12:01 +03007581 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007582 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007583
Johan Hedbergc80da272012-02-22 15:38:48 +02007584 memset(hdev->eir, 0, sizeof(hdev->eir));
7585
Johan Hedbergcacaf522012-02-21 00:52:42 +02007586 memset(&cp, 0, sizeof(cp));
7587
Johan Hedberg890ea892013-03-15 17:06:52 -05007588 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007589}
7590
Marcel Holtmann3e248562013-10-15 14:26:25 -07007591void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007592{
7593 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007594 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007595 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007596
7597 if (status) {
7598 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007599
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007600 if (enable && hci_dev_test_and_clear_flag(hdev,
7601 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007602 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007603 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007604 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007605
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007606 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7607 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007608 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007609 }
7610
7611 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007612 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007613 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007614 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007615 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007616 changed = hci_dev_test_and_clear_flag(hdev,
7617 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007618 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007619 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007620 }
7621
7622 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7623
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007624 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007625 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007626
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007627 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007628 sock_put(match.sk);
7629
Johan Hedberg890ea892013-03-15 17:06:52 -05007630 hci_req_init(&req, hdev);
7631
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007632 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7633 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007634 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7635 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007636 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007637 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007638 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007639 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007640
7641 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007642}
7643
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007644static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007645{
7646 struct cmd_lookup *match = data;
7647
Johan Hedberg90e70452012-02-23 23:09:40 +02007648 if (match->sk == NULL) {
7649 match->sk = cmd->sk;
7650 sock_hold(match->sk);
7651 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007652}
7653
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007654void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7655 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007656{
Johan Hedberg90e70452012-02-23 23:09:40 +02007657 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007658
Johan Hedberg92da6092013-03-15 17:06:55 -05007659 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7660 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7661 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007662
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007663 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007664 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7665 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007666 ext_info_changed(hdev, NULL);
7667 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007668
7669 if (match.sk)
7670 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007671}
7672
Marcel Holtmann7667da32013-10-15 14:26:27 -07007673void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007674{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007675 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007676 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007677
Johan Hedberg13928972013-03-15 17:07:00 -05007678 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007679 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007680
7681 memset(&ev, 0, sizeof(ev));
7682 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007683 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007684
Johan Hedberg333ae952015-03-17 13:48:47 +02007685 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007686 if (!cmd) {
7687 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007688
Johan Hedberg13928972013-03-15 17:07:00 -05007689 /* If this is a HCI command related to powering on the
7690 * HCI dev don't send any mgmt signals.
7691 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007692 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007693 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007694 }
7695
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007696 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7697 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007698 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007699}
Szymon Jancc35938b2011-03-22 13:12:21 +01007700
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007701static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7702{
7703 int i;
7704
7705 for (i = 0; i < uuid_count; i++) {
7706 if (!memcmp(uuid, uuids[i], 16))
7707 return true;
7708 }
7709
7710 return false;
7711}
7712
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007713static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7714{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007715 u16 parsed = 0;
7716
7717 while (parsed < eir_len) {
7718 u8 field_len = eir[0];
7719 u8 uuid[16];
7720 int i;
7721
7722 if (field_len == 0)
7723 break;
7724
7725 if (eir_len - parsed < field_len + 1)
7726 break;
7727
7728 switch (eir[1]) {
7729 case EIR_UUID16_ALL:
7730 case EIR_UUID16_SOME:
7731 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007732 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007733 uuid[13] = eir[i + 3];
7734 uuid[12] = eir[i + 2];
7735 if (has_uuid(uuid, uuid_count, uuids))
7736 return true;
7737 }
7738 break;
7739 case EIR_UUID32_ALL:
7740 case EIR_UUID32_SOME:
7741 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007742 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007743 uuid[15] = eir[i + 5];
7744 uuid[14] = eir[i + 4];
7745 uuid[13] = eir[i + 3];
7746 uuid[12] = eir[i + 2];
7747 if (has_uuid(uuid, uuid_count, uuids))
7748 return true;
7749 }
7750 break;
7751 case EIR_UUID128_ALL:
7752 case EIR_UUID128_SOME:
7753 for (i = 0; i + 17 <= field_len; i += 16) {
7754 memcpy(uuid, eir + i + 2, 16);
7755 if (has_uuid(uuid, uuid_count, uuids))
7756 return true;
7757 }
7758 break;
7759 }
7760
7761 parsed += field_len + 1;
7762 eir += field_len + 1;
7763 }
7764
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007765 return false;
7766}
7767
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007768static void restart_le_scan(struct hci_dev *hdev)
7769{
7770 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007771 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007772 return;
7773
7774 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7775 hdev->discovery.scan_start +
7776 hdev->discovery.scan_duration))
7777 return;
7778
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007779 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007780 DISCOV_LE_RESTART_DELAY);
7781}
7782
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007783static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7784 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7785{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007786 /* If a RSSI threshold has been specified, and
7787 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7788 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7789 * is set, let it through for further processing, as we might need to
7790 * restart the scan.
7791 *
7792 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7793 * the results are also dropped.
7794 */
7795 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7796 (rssi == HCI_RSSI_INVALID ||
7797 (rssi < hdev->discovery.rssi &&
7798 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7799 return false;
7800
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007801 if (hdev->discovery.uuid_count != 0) {
7802 /* If a list of UUIDs is provided in filter, results with no
7803 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007804 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007805 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7806 hdev->discovery.uuids) &&
7807 !eir_has_uuids(scan_rsp, scan_rsp_len,
7808 hdev->discovery.uuid_count,
7809 hdev->discovery.uuids))
7810 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007811 }
7812
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007813 /* If duplicate filtering does not report RSSI changes, then restart
7814 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007815 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007816 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7817 restart_le_scan(hdev);
7818
7819 /* Validate RSSI value against the RSSI threshold once more. */
7820 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7821 rssi < hdev->discovery.rssi)
7822 return false;
7823 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007824
7825 return true;
7826}
7827
Marcel Holtmann901801b2013-10-06 23:55:51 -07007828void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007829 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7830 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007831{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007832 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007833 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007834 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007835
Johan Hedberg75ce2082014-07-02 22:42:01 +03007836 /* Don't send events for a non-kernel initiated discovery. With
7837 * LE one exception is if we have pend_le_reports > 0 in which
7838 * case we're doing passive scanning and want these events.
7839 */
7840 if (!hci_discovery_active(hdev)) {
7841 if (link_type == ACL_LINK)
7842 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007843 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007844 return;
7845 }
Andre Guedes12602d02013-04-30 15:29:40 -03007846
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007847 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007848 /* We are using service discovery */
7849 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7850 scan_rsp_len))
7851 return;
7852 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007853
Johan Hedberg78b781c2016-01-05 13:19:32 +02007854 if (hdev->discovery.limited) {
7855 /* Check for limited discoverable bit */
7856 if (dev_class) {
7857 if (!(dev_class[1] & 0x20))
7858 return;
7859 } else {
7860 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7861 if (!flags || !(flags[0] & LE_AD_LIMITED))
7862 return;
7863 }
7864 }
7865
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007866 /* Make sure that the buffer is big enough. The 5 extra bytes
7867 * are for the potential CoD field.
7868 */
7869 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007870 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007871
Johan Hedberg1dc06092012-01-15 21:01:23 +02007872 memset(buf, 0, sizeof(buf));
7873
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007874 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7875 * RSSI value was reported as 0 when not available. This behavior
7876 * is kept when using device discovery. This is required for full
7877 * backwards compatibility with the API.
7878 *
7879 * However when using service discovery, the value 127 will be
7880 * returned when the RSSI is not available.
7881 */
Szymon Janc91200e92015-01-22 16:57:05 +01007882 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7883 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007884 rssi = 0;
7885
Johan Hedberg841c5642014-07-07 12:45:54 +03007886 bacpy(&ev->addr.bdaddr, bdaddr);
7887 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007888 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007889 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007890
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007891 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007892 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007893 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007894
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007895 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7896 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007897 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007898 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007899
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007900 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007901 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007902 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007903
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007904 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7905 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007906
Marcel Holtmann901801b2013-10-06 23:55:51 -07007907 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007908}
Johan Hedberga88a9652011-03-30 13:18:12 +03007909
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007910void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7911 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007912{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007913 struct mgmt_ev_device_found *ev;
7914 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7915 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007916
Johan Hedbergb644ba32012-01-17 21:48:47 +02007917 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007918
Johan Hedbergb644ba32012-01-17 21:48:47 +02007919 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007920
Johan Hedbergb644ba32012-01-17 21:48:47 +02007921 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007922 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007923 ev->rssi = rssi;
7924
7925 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007926 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007927
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007928 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007929
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007930 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007931}
Johan Hedberg314b2382011-04-27 10:29:57 -04007932
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007933void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007934{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007935 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007936
Andre Guedes343fb142011-11-22 17:14:19 -03007937 BT_DBG("%s discovering %u", hdev->name, discovering);
7938
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007939 memset(&ev, 0, sizeof(ev));
7940 ev.type = hdev->discovery.type;
7941 ev.discovering = discovering;
7942
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007943 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007944}
Antti Julku5e762442011-08-25 16:48:02 +03007945
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007946static struct hci_mgmt_chan chan = {
7947 .channel = HCI_CHANNEL_CONTROL,
7948 .handler_count = ARRAY_SIZE(mgmt_handlers),
7949 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007950 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007951};
7952
7953int mgmt_init(void)
7954{
7955 return hci_mgmt_chan_register(&chan);
7956}
7957
7958void mgmt_exit(void)
7959{
7960 hci_mgmt_chan_unregister(&chan);
7961}