blob: 761a9aeaa8247503e80de25216164aca77504648 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Szymon Janc33102302016-09-18 12:50:07 +020041#define MGMT_REVISION 14
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200106 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200107 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200108 MGMT_OP_SET_APPEARANCE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200109};
110
111static const u16 mgmt_events[] = {
112 MGMT_EV_CONTROLLER_ERROR,
113 MGMT_EV_INDEX_ADDED,
114 MGMT_EV_INDEX_REMOVED,
115 MGMT_EV_NEW_SETTINGS,
116 MGMT_EV_CLASS_OF_DEV_CHANGED,
117 MGMT_EV_LOCAL_NAME_CHANGED,
118 MGMT_EV_NEW_LINK_KEY,
119 MGMT_EV_NEW_LONG_TERM_KEY,
120 MGMT_EV_DEVICE_CONNECTED,
121 MGMT_EV_DEVICE_DISCONNECTED,
122 MGMT_EV_CONNECT_FAILED,
123 MGMT_EV_PIN_CODE_REQUEST,
124 MGMT_EV_USER_CONFIRM_REQUEST,
125 MGMT_EV_USER_PASSKEY_REQUEST,
126 MGMT_EV_AUTH_FAILED,
127 MGMT_EV_DEVICE_FOUND,
128 MGMT_EV_DISCOVERING,
129 MGMT_EV_DEVICE_BLOCKED,
130 MGMT_EV_DEVICE_UNBLOCKED,
131 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300132 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800133 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700134 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200135 MGMT_EV_DEVICE_ADDED,
136 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300137 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200138 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200139 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200140 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700141 MGMT_EV_EXT_INDEX_ADDED,
142 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700143 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700144 MGMT_EV_ADVERTISING_ADDED,
145 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200146 MGMT_EV_EXT_INFO_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200147};
148
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700149static const u16 mgmt_untrusted_commands[] = {
150 MGMT_OP_READ_INDEX_LIST,
151 MGMT_OP_READ_INFO,
152 MGMT_OP_READ_UNCONF_INDEX_LIST,
153 MGMT_OP_READ_CONFIG_INFO,
154 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200155 MGMT_OP_READ_EXT_INFO,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700156};
157
158static const u16 mgmt_untrusted_events[] = {
159 MGMT_EV_INDEX_ADDED,
160 MGMT_EV_INDEX_REMOVED,
161 MGMT_EV_NEW_SETTINGS,
162 MGMT_EV_CLASS_OF_DEV_CHANGED,
163 MGMT_EV_LOCAL_NAME_CHANGED,
164 MGMT_EV_UNCONF_INDEX_ADDED,
165 MGMT_EV_UNCONF_INDEX_REMOVED,
166 MGMT_EV_NEW_CONFIG_OPTIONS,
167 MGMT_EV_EXT_INDEX_ADDED,
168 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200169 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700170};
171
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800172#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200173
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200174#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
175 "\x00\x00\x00\x00\x00\x00\x00\x00"
176
Johan Hedbergca69b792011-11-11 18:10:00 +0200177/* HCI to MGMT error code conversion table */
178static u8 mgmt_status_table[] = {
179 MGMT_STATUS_SUCCESS,
180 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
181 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
182 MGMT_STATUS_FAILED, /* Hardware Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
184 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200185 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200186 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
187 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
188 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
189 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
190 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
191 MGMT_STATUS_BUSY, /* Command Disallowed */
192 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
193 MGMT_STATUS_REJECTED, /* Rejected Security */
194 MGMT_STATUS_REJECTED, /* Rejected Personal */
195 MGMT_STATUS_TIMEOUT, /* Host Timeout */
196 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
197 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
198 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
199 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
200 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
201 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
202 MGMT_STATUS_BUSY, /* Repeated Attempts */
203 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
204 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
206 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
207 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
208 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
209 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
210 MGMT_STATUS_FAILED, /* Unspecified Error */
211 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
212 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
213 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
214 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
215 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
216 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
217 MGMT_STATUS_FAILED, /* Unit Link Key Used */
218 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
219 MGMT_STATUS_TIMEOUT, /* Instant Passed */
220 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
221 MGMT_STATUS_FAILED, /* Transaction Collision */
222 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
223 MGMT_STATUS_REJECTED, /* QoS Rejected */
224 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
225 MGMT_STATUS_REJECTED, /* Insufficient Security */
226 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
227 MGMT_STATUS_BUSY, /* Role Switch Pending */
228 MGMT_STATUS_FAILED, /* Slot Violation */
229 MGMT_STATUS_FAILED, /* Role Switch Failed */
230 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
231 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
232 MGMT_STATUS_BUSY, /* Host Busy Pairing */
233 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
234 MGMT_STATUS_BUSY, /* Controller Busy */
235 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
236 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
237 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
238 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
239 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
240};
241
242static u8 mgmt_status(u8 hci_status)
243{
244 if (hci_status < ARRAY_SIZE(mgmt_status_table))
245 return mgmt_status_table[hci_status];
246
247 return MGMT_STATUS_FAILED;
248}
249
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700250static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
251 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700252{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700253 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
254 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700255}
256
Marcel Holtmann72000df2015-03-16 16:11:21 -0700257static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
258 u16 len, int flag, struct sock *skip_sk)
259{
260 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
261 flag, skip_sk);
262}
263
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200264static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
265 struct sock *skip_sk)
266{
267 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700268 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200269}
270
Johan Hedberg85813a72015-10-21 18:02:59 +0300271static u8 le_addr_type(u8 mgmt_addr_type)
272{
273 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
274 return ADDR_LE_DEV_PUBLIC;
275 else
276 return ADDR_LE_DEV_RANDOM;
277}
278
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200279void mgmt_fill_version_info(void *ver)
280{
281 struct mgmt_rp_read_version *rp = ver;
282
283 rp->version = MGMT_VERSION;
284 rp->revision = cpu_to_le16(MGMT_REVISION);
285}
286
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300287static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
288 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200289{
290 struct mgmt_rp_read_version rp;
291
292 BT_DBG("sock %p", sk);
293
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200294 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200295
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200296 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
297 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200298}
299
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300300static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
301 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302{
303 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305 size_t rp_size;
306 int i, err;
307
308 BT_DBG("sock %p", sk);
309
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700310 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
311 num_commands = ARRAY_SIZE(mgmt_commands);
312 num_events = ARRAY_SIZE(mgmt_events);
313 } else {
314 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
315 num_events = ARRAY_SIZE(mgmt_untrusted_events);
316 }
317
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200318 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
319
320 rp = kmalloc(rp_size, GFP_KERNEL);
321 if (!rp)
322 return -ENOMEM;
323
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700324 rp->num_commands = cpu_to_le16(num_commands);
325 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200326
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700327 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
328 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200329
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700330 for (i = 0; i < num_commands; i++, opcode++)
331 put_unaligned_le16(mgmt_commands[i], opcode);
332
333 for (i = 0; i < num_events; i++, opcode++)
334 put_unaligned_le16(mgmt_events[i], opcode);
335 } else {
336 __le16 *opcode = rp->opcodes;
337
338 for (i = 0; i < num_commands; i++, opcode++)
339 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
340
341 for (i = 0; i < num_events; i++, opcode++)
342 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
343 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200344
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200345 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
346 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200347 kfree(rp);
348
349 return err;
350}
351
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300352static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
353 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200356 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300359 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
361 BT_DBG("sock %p", sk);
362
363 read_lock(&hci_dev_list_lock);
364
365 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300366 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200367 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700368 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700369 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 }
371
Johan Hedberga38528f2011-01-22 06:46:43 +0200372 rp_len = sizeof(*rp) + (2 * count);
373 rp = kmalloc(rp_len, GFP_ATOMIC);
374 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100375 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200376 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100377 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200378
Johan Hedberg476e44c2012-10-19 20:10:46 +0300379 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200380 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700381 if (hci_dev_test_flag(d, HCI_SETUP) ||
382 hci_dev_test_flag(d, HCI_CONFIG) ||
383 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 /* Devices marked as raw-only are neither configured
387 * nor unconfigured controllers.
388 */
389 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700390 continue;
391
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200392 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700393 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700394 rp->index[count++] = cpu_to_le16(d->id);
395 BT_DBG("Added hci%u", d->id);
396 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200397 }
398
Johan Hedberg476e44c2012-10-19 20:10:46 +0300399 rp->num_controllers = cpu_to_le16(count);
400 rp_len = sizeof(*rp) + (2 * count);
401
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200402 read_unlock(&hci_dev_list_lock);
403
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200404 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
405 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200406
Johan Hedberga38528f2011-01-22 06:46:43 +0200407 kfree(rp);
408
409 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200410}
411
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200412static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
413 void *data, u16 data_len)
414{
415 struct mgmt_rp_read_unconf_index_list *rp;
416 struct hci_dev *d;
417 size_t rp_len;
418 u16 count;
419 int err;
420
421 BT_DBG("sock %p", sk);
422
423 read_lock(&hci_dev_list_lock);
424
425 count = 0;
426 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200427 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700428 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200429 count++;
430 }
431
432 rp_len = sizeof(*rp) + (2 * count);
433 rp = kmalloc(rp_len, GFP_ATOMIC);
434 if (!rp) {
435 read_unlock(&hci_dev_list_lock);
436 return -ENOMEM;
437 }
438
439 count = 0;
440 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700441 if (hci_dev_test_flag(d, HCI_SETUP) ||
442 hci_dev_test_flag(d, HCI_CONFIG) ||
443 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200444 continue;
445
446 /* Devices marked as raw-only are neither configured
447 * nor unconfigured controllers.
448 */
449 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
450 continue;
451
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200452 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700453 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200454 rp->index[count++] = cpu_to_le16(d->id);
455 BT_DBG("Added hci%u", d->id);
456 }
457 }
458
459 rp->num_controllers = cpu_to_le16(count);
460 rp_len = sizeof(*rp) + (2 * count);
461
462 read_unlock(&hci_dev_list_lock);
463
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200464 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
465 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200466
467 kfree(rp);
468
469 return err;
470}
471
Marcel Holtmann96f14742015-03-14 19:27:57 -0700472static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
473 void *data, u16 data_len)
474{
475 struct mgmt_rp_read_ext_index_list *rp;
476 struct hci_dev *d;
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 Holtmann08dc0e982015-03-25 18:32:13 -0700834 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800835 * address is actually used decides if the flag is set or not.
836 *
837 * For single mode LE only controllers and dual-mode controllers
838 * with BR/EDR disabled, the existence of the static address will
839 * be evaluated.
840 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700841 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700842 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800843 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
844 if (bacmp(&hdev->static_addr, BDADDR_ANY))
845 settings |= MGMT_SETTING_STATIC_ADDRESS;
846 }
847
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200848 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200849}
850
Johan Hedberg333ae952015-03-17 13:48:47 +0200851static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
852{
853 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
854}
855
Johan Hedberg333ae952015-03-17 13:48:47 +0200856static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
857 struct hci_dev *hdev,
858 const void *data)
859{
860 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
861}
862
Johan Hedbergf2252572015-11-18 12:49:20 +0200863u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300864{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200865 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300866
867 /* If there's a pending mgmt command the flags will not yet have
868 * their final values, so check for this first.
869 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200870 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300871 if (cmd) {
872 struct mgmt_mode *cp = cmd->param;
873 if (cp->val == 0x01)
874 return LE_AD_GENERAL;
875 else if (cp->val == 0x02)
876 return LE_AD_LIMITED;
877 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700878 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300879 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700880 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300881 return LE_AD_GENERAL;
882 }
883
884 return 0;
885}
886
Johan Hedbergf2252572015-11-18 12:49:20 +0200887bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700888{
889 struct mgmt_pending_cmd *cmd;
890
891 /* If there's a pending mgmt command the flag will not yet have
892 * it's final value, so check for this first.
893 */
894 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
895 if (cmd) {
896 struct mgmt_mode *cp = cmd->param;
897
898 return cp->val;
899 }
900
901 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
902}
903
Johan Hedberg7d785252011-12-15 00:47:39 +0200904static void service_cache_off(struct work_struct *work)
905{
906 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300907 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500908 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200909
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700910 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200911 return;
912
Johan Hedberg890ea892013-03-15 17:06:52 -0500913 hci_req_init(&req, hdev);
914
Johan Hedberg7d785252011-12-15 00:47:39 +0200915 hci_dev_lock(hdev);
916
Johan Hedbergb1a89172015-11-25 16:15:42 +0200917 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200918 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200919
920 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500921
922 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200923}
924
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200925static void rpa_expired(struct work_struct *work)
926{
927 struct hci_dev *hdev = container_of(work, struct hci_dev,
928 rpa_expired.work);
929 struct hci_request req;
930
931 BT_DBG("");
932
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700933 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200934
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700935 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200936 return;
937
938 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200939 * controller happens in the hci_req_enable_advertising()
940 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200941 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200942 hci_req_init(&req, hdev);
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +0530943 if (ext_adv_capable(hdev))
944 __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
945 else
946 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200947 hci_req_run(&req, NULL);
948}
949
Johan Hedberg6a919082012-02-28 06:17:26 +0200950static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200951{
Marcel Holtmann238be782015-03-13 02:11:06 -0700952 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200953 return;
954
Johan Hedberg4f87da82012-03-02 19:55:56 +0200955 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200956 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200957
Johan Hedberg4f87da82012-03-02 19:55:56 +0200958 /* Non-mgmt controlled devices get this bit set
959 * implicitly so that pairing works for them, however
960 * for mgmt we require user-space to explicitly enable
961 * it
962 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700963 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200964}
965
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200966static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300967 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200968{
969 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200970
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200971 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200972
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300973 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200974
Johan Hedberg03811012010-12-08 00:21:06 +0200975 memset(&rp, 0, sizeof(rp));
976
Johan Hedberg03811012010-12-08 00:21:06 +0200977 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200978
979 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200980 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200981
982 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
983 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
984
985 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200986
987 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200988 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200989
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300990 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200991
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200992 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
993 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200994}
995
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +0200996static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
997{
998 u16 eir_len = 0;
999 size_t name_len;
1000
1001 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1002 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
1003 hdev->dev_class, 3);
1004
Szymon Janc6a9e90b2016-09-19 20:25:54 +02001005 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1006 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
1007 hdev->appearance);
1008
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001009 name_len = strlen(hdev->dev_name);
1010 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
1011 hdev->dev_name, name_len);
1012
1013 name_len = strlen(hdev->short_name);
1014 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
1015 hdev->short_name, name_len);
1016
1017 return eir_len;
1018}
1019
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001020static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
1021 void *data, u16 data_len)
1022{
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001023 char buf[512];
1024 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001025 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001026
1027 BT_DBG("sock %p %s", sk, hdev->name);
1028
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001029 memset(&buf, 0, sizeof(buf));
1030
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001031 hci_dev_lock(hdev);
1032
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001033 bacpy(&rp->bdaddr, &hdev->bdaddr);
1034
1035 rp->version = hdev->hci_ver;
1036 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
1037
1038 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
1039 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001040
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001041
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +02001042 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +02001043 rp->eir_len = cpu_to_le16(eir_len);
1044
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001045 hci_dev_unlock(hdev);
1046
1047 /* If this command is called at least once, then the events
1048 * for class of device and local name changes are disabled
1049 * and only the new extended controller information event
1050 * is used.
1051 */
1052 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
1053 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
1054 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
1055
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +02001056 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
1057 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001058}
1059
1060static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
1061{
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001062 char buf[512];
1063 struct mgmt_ev_ext_info_changed *ev = (void *)buf;
1064 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001065
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001066 memset(buf, 0, sizeof(buf));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001067
MichaƂ Narajowski5e9fae42016-09-19 20:25:55 +02001068 eir_len = append_eir_data_to_buf(hdev, ev->eir);
1069 ev->eir_len = cpu_to_le16(eir_len);
1070
1071 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
1072 sizeof(*ev) + eir_len,
1073 HCI_MGMT_EXT_INFO_EVENTS, skip);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02001074}
1075
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001076static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001077{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001078 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001079
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001080 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1081 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001082}
1083
Marcel Holtmann1904a852015-01-11 13:50:44 -08001084static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001085{
1086 BT_DBG("%s status 0x%02x", hdev->name, status);
1087
Johan Hedberga3172b72014-02-28 09:33:44 +02001088 if (hci_conn_count(hdev) == 0) {
1089 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001090 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001091 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001092}
1093
Johan Hedbergf2252572015-11-18 12:49:20 +02001094void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001095{
1096 struct mgmt_ev_advertising_added ev;
1097
1098 ev.instance = instance;
1099
1100 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1101}
1102
Johan Hedbergf2252572015-11-18 12:49:20 +02001103void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1104 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001105{
1106 struct mgmt_ev_advertising_removed ev;
1107
1108 ev.instance = instance;
1109
1110 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1111}
1112
Florian Grandel7816b822015-06-18 03:16:45 +02001113static void cancel_adv_timeout(struct hci_dev *hdev)
1114{
1115 if (hdev->adv_instance_timeout) {
1116 hdev->adv_instance_timeout = 0;
1117 cancel_delayed_work(&hdev->adv_instance_expire);
1118 }
1119}
1120
Johan Hedberg8b064a32014-02-24 14:52:22 +02001121static int clean_up_hci_state(struct hci_dev *hdev)
1122{
1123 struct hci_request req;
1124 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001125 bool discov_stopped;
1126 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001127
1128 hci_req_init(&req, hdev);
1129
1130 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1131 test_bit(HCI_PSCAN, &hdev->flags)) {
1132 u8 scan = 0x00;
1133 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1134 }
1135
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001136 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001137
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001138 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001139 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001140
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001141 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001142
1143 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001144 /* 0x15 == Terminated due to Power Off */
1145 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001146 }
1147
Johan Hedberg23a48092014-07-08 16:05:06 +03001148 err = hci_req_run(&req, clean_up_hci_complete);
1149 if (!err && discov_stopped)
1150 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1151
1152 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001153}
1154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001155static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001156 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001157{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001158 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001159 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001160 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001162 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001163
Johan Hedberga7e80f22013-01-09 16:05:19 +02001164 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001165 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1166 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001168 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001169
Johan Hedberg333ae952015-03-17 13:48:47 +02001170 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001171 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1172 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001173 goto failed;
1174 }
1175
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001176 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001177 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001178 goto failed;
1179 }
1180
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001181 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1182 if (!cmd) {
1183 err = -ENOMEM;
1184 goto failed;
1185 }
1186
Johan Hedberg8b064a32014-02-24 14:52:22 +02001187 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001188 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001189 err = 0;
1190 } else {
1191 /* Disconnect connections, stop scans, etc */
1192 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001193 if (!err)
1194 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1195 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
Johan Hedberg8b064a32014-02-24 14:52:22 +02001197 /* ENODATA means there were no HCI commands queued */
1198 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001199 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001200 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1201 err = 0;
1202 }
1203 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001204
1205failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001206 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207 return err;
1208}
1209
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001210static int new_settings(struct hci_dev *hdev, struct sock *skip)
1211{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001212 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001213
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001214 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1215 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001216}
1217
Johan Hedberg91a668b2014-07-09 13:28:26 +03001218int mgmt_new_settings(struct hci_dev *hdev)
1219{
1220 return new_settings(hdev, NULL);
1221}
1222
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001223struct cmd_lookup {
1224 struct sock *sk;
1225 struct hci_dev *hdev;
1226 u8 mgmt_status;
1227};
1228
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001229static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001230{
1231 struct cmd_lookup *match = data;
1232
1233 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1234
1235 list_del(&cmd->list);
1236
1237 if (match->sk == NULL) {
1238 match->sk = cmd->sk;
1239 sock_hold(match->sk);
1240 }
1241
1242 mgmt_pending_free(cmd);
1243}
1244
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001245static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001246{
1247 u8 *status = data;
1248
Johan Hedberga69e8372015-03-06 21:08:53 +02001249 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001250 mgmt_pending_remove(cmd);
1251}
1252
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001253static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001254{
1255 if (cmd->cmd_complete) {
1256 u8 *status = data;
1257
1258 cmd->cmd_complete(cmd, *status);
1259 mgmt_pending_remove(cmd);
1260
1261 return;
1262 }
1263
1264 cmd_status_rsp(cmd, data);
1265}
1266
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001267static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001268{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001269 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1270 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001271}
1272
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001273static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001274{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001275 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1276 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001277}
1278
Johan Hedberge6fe7982013-10-02 15:45:22 +03001279static u8 mgmt_bredr_support(struct hci_dev *hdev)
1280{
1281 if (!lmp_bredr_capable(hdev))
1282 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001283 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001284 return MGMT_STATUS_REJECTED;
1285 else
1286 return MGMT_STATUS_SUCCESS;
1287}
1288
1289static u8 mgmt_le_support(struct hci_dev *hdev)
1290{
1291 if (!lmp_le_capable(hdev))
1292 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001293 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001294 return MGMT_STATUS_REJECTED;
1295 else
1296 return MGMT_STATUS_SUCCESS;
1297}
1298
Johan Hedbergaed1a882015-11-22 17:24:44 +03001299void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001300{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001301 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001302
1303 BT_DBG("status 0x%02x", status);
1304
1305 hci_dev_lock(hdev);
1306
Johan Hedberg333ae952015-03-17 13:48:47 +02001307 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001308 if (!cmd)
1309 goto unlock;
1310
1311 if (status) {
1312 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001313 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001314 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001315 goto remove_cmd;
1316 }
1317
Johan Hedbergaed1a882015-11-22 17:24:44 +03001318 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1319 hdev->discov_timeout > 0) {
1320 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1321 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001322 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001323
1324 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001325 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001326
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001327remove_cmd:
1328 mgmt_pending_remove(cmd);
1329
1330unlock:
1331 hci_dev_unlock(hdev);
1332}
1333
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001334static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001335 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001336{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001337 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001338 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001339 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001340 int err;
1341
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001343
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001344 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1345 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001346 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1347 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001348
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001349 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001350 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1351 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001352
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001353 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001354
1355 /* Disabling discoverable requires that no timeout is set,
1356 * and enabling limited discoverable requires a timeout.
1357 */
1358 if ((cp->val == 0x00 && timeout > 0) ||
1359 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001360 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001363 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001364
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001365 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001366 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1367 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001368 goto failed;
1369 }
1370
Johan Hedberg333ae952015-03-17 13:48:47 +02001371 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1372 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001373 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1374 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001375 goto failed;
1376 }
1377
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001378 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001379 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1380 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001381 goto failed;
1382 }
1383
1384 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001385 bool changed = false;
1386
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001387 /* Setting limited discoverable when powered off is
1388 * not a valid operation since it requires a timeout
1389 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1390 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001391 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001392 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001393 changed = true;
1394 }
1395
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001396 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001397 if (err < 0)
1398 goto failed;
1399
1400 if (changed)
1401 err = new_settings(hdev, sk);
1402
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001403 goto failed;
1404 }
1405
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001406 /* If the current mode is the same, then just update the timeout
1407 * value with the new value. And if only the timeout gets updated,
1408 * then no need for any HCI transactions.
1409 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001410 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1411 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1412 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001413 cancel_delayed_work(&hdev->discov_off);
1414 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001415
Marcel Holtmann36261542013-10-15 08:28:51 -07001416 if (cp->val && hdev->discov_timeout > 0) {
1417 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001418 queue_delayed_work(hdev->req_workqueue,
1419 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001420 }
1421
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001422 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001423 goto failed;
1424 }
1425
1426 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1427 if (!cmd) {
1428 err = -ENOMEM;
1429 goto failed;
1430 }
1431
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001432 /* Cancel any potential discoverable timeout that might be
1433 * still active and store new timeout value. The arming of
1434 * the timeout happens in the complete handler.
1435 */
1436 cancel_delayed_work(&hdev->discov_off);
1437 hdev->discov_timeout = timeout;
1438
Johan Hedbergaed1a882015-11-22 17:24:44 +03001439 if (cp->val)
1440 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1441 else
1442 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1443
Johan Hedbergb456f872013-10-19 23:38:22 +03001444 /* Limited discoverable mode */
1445 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001446 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001447 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001448 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001449
Johan Hedbergaed1a882015-11-22 17:24:44 +03001450 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1451 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001452
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001453failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001454 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001455 return err;
1456}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001457
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001458void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001459{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001460 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001461
1462 BT_DBG("status 0x%02x", status);
1463
1464 hci_dev_lock(hdev);
1465
Johan Hedberg333ae952015-03-17 13:48:47 +02001466 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001467 if (!cmd)
1468 goto unlock;
1469
Johan Hedberg37438c12013-10-14 16:20:05 +03001470 if (status) {
1471 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001472 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001473 goto remove_cmd;
1474 }
1475
Johan Hedberg2b76f452013-03-15 17:07:04 -05001476 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001477 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001478
Johan Hedberg37438c12013-10-14 16:20:05 +03001479remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001480 mgmt_pending_remove(cmd);
1481
1482unlock:
1483 hci_dev_unlock(hdev);
1484}
1485
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001486static int set_connectable_update_settings(struct hci_dev *hdev,
1487 struct sock *sk, u8 val)
1488{
1489 bool changed = false;
1490 int err;
1491
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001492 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001493 changed = true;
1494
1495 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001496 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001497 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001498 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1499 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001500 }
1501
1502 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1503 if (err < 0)
1504 return err;
1505
Johan Hedberg562064e2014-07-08 16:35:34 +03001506 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001507 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001508 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001509 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001510 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001511
1512 return 0;
1513}
1514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001515static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001516 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001517{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001518 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001519 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001520 int err;
1521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001522 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001523
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001524 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1525 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001526 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1527 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001528
Johan Hedberga7e80f22013-01-09 16:05:19 +02001529 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001530 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1531 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001532
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001533 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001534
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001535 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001536 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001537 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001538 }
1539
Johan Hedberg333ae952015-03-17 13:48:47 +02001540 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1541 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001542 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1543 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001544 goto failed;
1545 }
1546
Johan Hedberg73f22f62010-12-29 16:00:25 +02001547 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1548 if (!cmd) {
1549 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001550 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001551 }
1552
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001553 if (cp->val) {
1554 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1555 } else {
1556 if (hdev->discov_timeout > 0)
1557 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001558
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001559 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1560 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1561 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001562 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001563
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001564 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1565 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001566
1567failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001568 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001569 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001570}
1571
Johan Hedbergb2939472014-07-30 09:22:23 +03001572static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001573 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001574{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001575 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001576 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001577 int err;
1578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001579 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001580
Johan Hedberga7e80f22013-01-09 16:05:19 +02001581 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001582 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1583 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001584
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001585 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001586
1587 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001588 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001589 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001590 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001591
Johan Hedbergb2939472014-07-30 09:22:23 +03001592 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001593 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001594 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001595
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001596 if (changed) {
1597 /* In limited privacy mode the change of bondable mode
1598 * may affect the local advertising address.
1599 */
1600 if (hdev_is_powered(hdev) &&
1601 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1602 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1603 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1604 queue_work(hdev->req_workqueue,
1605 &hdev->discoverable_update);
1606
Marcel Holtmann55594352013-10-06 16:11:57 -07001607 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001608 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001609
Marcel Holtmann55594352013-10-06 16:11:57 -07001610unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001611 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001612 return err;
1613}
1614
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001615static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1616 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001617{
1618 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001619 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001620 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001621 int err;
1622
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001623 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001624
Johan Hedberge6fe7982013-10-02 15:45:22 +03001625 status = mgmt_bredr_support(hdev);
1626 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001627 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1628 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001629
Johan Hedberga7e80f22013-01-09 16:05:19 +02001630 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001631 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001633
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001634 hci_dev_lock(hdev);
1635
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001636 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001637 bool changed = false;
1638
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001639 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001640 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001641 changed = true;
1642 }
1643
1644 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1645 if (err < 0)
1646 goto failed;
1647
1648 if (changed)
1649 err = new_settings(hdev, sk);
1650
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001651 goto failed;
1652 }
1653
Johan Hedberg333ae952015-03-17 13:48:47 +02001654 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001655 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1656 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001657 goto failed;
1658 }
1659
1660 val = !!cp->val;
1661
1662 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1663 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1664 goto failed;
1665 }
1666
1667 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1668 if (!cmd) {
1669 err = -ENOMEM;
1670 goto failed;
1671 }
1672
1673 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1674 if (err < 0) {
1675 mgmt_pending_remove(cmd);
1676 goto failed;
1677 }
1678
1679failed:
1680 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001681 return err;
1682}
1683
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001684static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001685{
1686 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001687 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001688 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001689 int err;
1690
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001691 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001692
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001693 status = mgmt_bredr_support(hdev);
1694 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001695 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001696
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001697 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001698 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1699 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001700
Johan Hedberga7e80f22013-01-09 16:05:19 +02001701 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001702 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1703 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001704
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001705 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001706
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001707 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001708 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001709
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001710 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001711 changed = !hci_dev_test_and_set_flag(hdev,
1712 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001713 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001714 changed = hci_dev_test_and_clear_flag(hdev,
1715 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001716 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001717 changed = hci_dev_test_and_clear_flag(hdev,
1718 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001719 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001720 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001721 }
1722
1723 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1724 if (err < 0)
1725 goto failed;
1726
1727 if (changed)
1728 err = new_settings(hdev, sk);
1729
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001730 goto failed;
1731 }
1732
Johan Hedberg333ae952015-03-17 13:48:47 +02001733 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001734 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1735 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001736 goto failed;
1737 }
1738
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001739 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001740 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1741 goto failed;
1742 }
1743
1744 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1745 if (!cmd) {
1746 err = -ENOMEM;
1747 goto failed;
1748 }
1749
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001750 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001751 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1752 sizeof(cp->val), &cp->val);
1753
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001754 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001755 if (err < 0) {
1756 mgmt_pending_remove(cmd);
1757 goto failed;
1758 }
1759
1760failed:
1761 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001762 return err;
1763}
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001766{
1767 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001768 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001769 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001770 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001772 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001773
Johan Hedberge6fe7982013-10-02 15:45:22 +03001774 status = mgmt_bredr_support(hdev);
1775 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001776 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001777
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001778 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001779 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1780 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001781
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001782 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001783 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1784 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001785
Johan Hedberga7e80f22013-01-09 16:05:19 +02001786 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001787 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1788 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001789
Marcel Holtmannee392692013-10-01 22:59:23 -07001790 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001791
Johan Hedberg333ae952015-03-17 13:48:47 +02001792 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001793 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1794 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001795 goto unlock;
1796 }
1797
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001798 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001799 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001800 } else {
1801 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001802 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1803 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001804 goto unlock;
1805 }
1806
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001807 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001808 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001809
1810 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1811 if (err < 0)
1812 goto unlock;
1813
1814 if (changed)
1815 err = new_settings(hdev, sk);
1816
1817unlock:
1818 hci_dev_unlock(hdev);
1819 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001820}
1821
Marcel Holtmann1904a852015-01-11 13:50:44 -08001822static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001823{
1824 struct cmd_lookup match = { NULL, hdev };
1825
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301826 hci_dev_lock(hdev);
1827
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001828 if (status) {
1829 u8 mgmt_err = mgmt_status(status);
1830
1831 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1832 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301833 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001834 }
1835
1836 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1837
1838 new_settings(hdev, match.sk);
1839
1840 if (match.sk)
1841 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001842
1843 /* Make sure the controller has a good default for
1844 * advertising data. Restrict the update to when LE
1845 * has actually been enabled. During power on, the
1846 * update in powered_update_hci will take care of it.
1847 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001848 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001849 struct hci_request req;
1850
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001851 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001852 __hci_req_update_adv_data(&req, 0x00);
1853 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001854 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001855 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001856 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301857
1858unlock:
1859 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001860}
1861
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001862static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001863{
1864 struct mgmt_mode *cp = data;
1865 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001866 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001867 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001868 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001869 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001870
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001871 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001872
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001873 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001874 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1875 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001876
Johan Hedberga7e80f22013-01-09 16:05:19 +02001877 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001878 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1879 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001880
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001881 /* Bluetooth single mode LE only controllers or dual-mode
1882 * controllers configured as LE only devices, do not allow
1883 * switching LE off. These have either LE enabled explicitly
1884 * or BR/EDR has been previously switched off.
1885 *
1886 * When trying to enable an already enabled LE, then gracefully
1887 * send a positive response. Trying to disable it however will
1888 * result into rejection.
1889 */
1890 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1891 if (cp->val == 0x01)
1892 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1893
Johan Hedberga69e8372015-03-06 21:08:53 +02001894 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1895 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001896 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001897
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001898 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001899
1900 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001901 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001902
Florian Grandel847818d2015-06-18 03:16:46 +02001903 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001904 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001905
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001906 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001907 bool changed = false;
1908
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001909 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001910 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001911 changed = true;
1912 }
1913
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001914 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001915 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001916 changed = true;
1917 }
1918
Johan Hedberg06199cf2012-02-22 16:37:11 +02001919 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1920 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001921 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001922
1923 if (changed)
1924 err = new_settings(hdev, sk);
1925
Johan Hedberg1de028c2012-02-29 19:55:35 -08001926 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001927 }
1928
Johan Hedberg333ae952015-03-17 13:48:47 +02001929 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1930 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001931 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1932 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001933 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001934 }
1935
1936 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1937 if (!cmd) {
1938 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001939 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001940 }
1941
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001942 hci_req_init(&req, hdev);
1943
Johan Hedberg06199cf2012-02-22 16:37:11 +02001944 memset(&hci_cp, 0, sizeof(hci_cp));
1945
1946 if (val) {
1947 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001948 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001949 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001950 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001951 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001952 }
1953
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001954 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1955 &hci_cp);
1956
1957 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301958 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001959 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001960
Johan Hedberg1de028c2012-02-29 19:55:35 -08001961unlock:
1962 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001963 return err;
1964}
1965
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001966/* This is a helper function to test for pending mgmt commands that can
1967 * cause CoD or EIR HCI commands. We can only allow one such pending
1968 * mgmt command at a time since otherwise we cannot easily track what
1969 * the current values are, will be, and based on that calculate if a new
1970 * HCI command needs to be sent and if yes with what value.
1971 */
1972static bool pending_eir_or_class(struct hci_dev *hdev)
1973{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001974 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001975
1976 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1977 switch (cmd->opcode) {
1978 case MGMT_OP_ADD_UUID:
1979 case MGMT_OP_REMOVE_UUID:
1980 case MGMT_OP_SET_DEV_CLASS:
1981 case MGMT_OP_SET_POWERED:
1982 return true;
1983 }
1984 }
1985
1986 return false;
1987}
1988
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001989static const u8 bluetooth_base_uuid[] = {
1990 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1991 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1992};
1993
1994static u8 get_uuid_size(const u8 *uuid)
1995{
1996 u32 val;
1997
1998 if (memcmp(uuid, bluetooth_base_uuid, 12))
1999 return 128;
2000
2001 val = get_unaligned_le32(&uuid[12]);
2002 if (val > 0xffff)
2003 return 32;
2004
2005 return 16;
2006}
2007
Johan Hedberg92da6092013-03-15 17:06:55 -05002008static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2009{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002010 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002011
2012 hci_dev_lock(hdev);
2013
Johan Hedberg333ae952015-03-17 13:48:47 +02002014 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002015 if (!cmd)
2016 goto unlock;
2017
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002018 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2019 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002020
2021 mgmt_pending_remove(cmd);
2022
2023unlock:
2024 hci_dev_unlock(hdev);
2025}
2026
Marcel Holtmann1904a852015-01-11 13:50:44 -08002027static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002028{
2029 BT_DBG("status 0x%02x", status);
2030
2031 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2032}
2033
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002034static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002035{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002036 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002037 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002038 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002039 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002040 int err;
2041
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002042 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002043
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002044 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002045
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002046 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002047 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2048 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002049 goto failed;
2050 }
2051
Andre Guedes92c4c202012-06-07 19:05:44 -03002052 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002053 if (!uuid) {
2054 err = -ENOMEM;
2055 goto failed;
2056 }
2057
2058 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002059 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002060 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002061
Johan Hedbergde66aa62013-01-27 00:31:27 +02002062 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063
Johan Hedberg890ea892013-03-15 17:06:52 -05002064 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002065
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002066 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002067 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002068
Johan Hedberg92da6092013-03-15 17:06:55 -05002069 err = hci_req_run(&req, add_uuid_complete);
2070 if (err < 0) {
2071 if (err != -ENODATA)
2072 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002073
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002074 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2075 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002076 goto failed;
2077 }
2078
2079 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002080 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002081 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002082 goto failed;
2083 }
2084
2085 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002086
2087failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002088 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089 return err;
2090}
2091
Johan Hedberg24b78d02012-02-23 23:24:30 +02002092static bool enable_service_cache(struct hci_dev *hdev)
2093{
2094 if (!hdev_is_powered(hdev))
2095 return false;
2096
Marcel Holtmann238be782015-03-13 02:11:06 -07002097 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002098 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2099 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002100 return true;
2101 }
2102
2103 return false;
2104}
2105
Marcel Holtmann1904a852015-01-11 13:50:44 -08002106static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002107{
2108 BT_DBG("status 0x%02x", status);
2109
2110 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2111}
2112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002113static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002114 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002115{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002116 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002117 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002118 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119 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 -05002120 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002121 int err, found;
2122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002123 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002125 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002126
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002127 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002128 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2129 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002130 goto unlock;
2131 }
2132
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002133 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002134 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002135
Johan Hedberg24b78d02012-02-23 23:24:30 +02002136 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002137 err = mgmt_cmd_complete(sk, hdev->id,
2138 MGMT_OP_REMOVE_UUID,
2139 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002140 goto unlock;
2141 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002142
Johan Hedberg9246a862012-02-23 21:33:16 +02002143 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002144 }
2145
2146 found = 0;
2147
Johan Hedberg056341c2013-01-27 00:31:30 +02002148 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002149 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2150 continue;
2151
2152 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002153 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002154 found++;
2155 }
2156
2157 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002158 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2159 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002160 goto unlock;
2161 }
2162
Johan Hedberg9246a862012-02-23 21:33:16 +02002163update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002164 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002165
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002166 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002167 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002168
Johan Hedberg92da6092013-03-15 17:06:55 -05002169 err = hci_req_run(&req, remove_uuid_complete);
2170 if (err < 0) {
2171 if (err != -ENODATA)
2172 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002173
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002174 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2175 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002176 goto unlock;
2177 }
2178
2179 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002180 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002181 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002182 goto unlock;
2183 }
2184
2185 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002186
2187unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002188 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002189 return err;
2190}
2191
Marcel Holtmann1904a852015-01-11 13:50:44 -08002192static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002193{
2194 BT_DBG("status 0x%02x", status);
2195
2196 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2197}
2198
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002199static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002200 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002201{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002202 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002203 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002204 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002205 int err;
2206
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002207 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002208
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002209 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002210 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2211 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002212
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002213 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002214
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002215 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002216 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2217 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002218 goto unlock;
2219 }
2220
2221 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002222 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2223 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002224 goto unlock;
2225 }
2226
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002227 hdev->major_class = cp->major;
2228 hdev->minor_class = cp->minor;
2229
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002230 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002231 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2232 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002233 goto unlock;
2234 }
2235
Johan Hedberg890ea892013-03-15 17:06:52 -05002236 hci_req_init(&req, hdev);
2237
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002238 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002239 hci_dev_unlock(hdev);
2240 cancel_delayed_work_sync(&hdev->service_cache);
2241 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002242 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002243 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002244
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002245 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002246
Johan Hedberg92da6092013-03-15 17:06:55 -05002247 err = hci_req_run(&req, set_class_complete);
2248 if (err < 0) {
2249 if (err != -ENODATA)
2250 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002251
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002252 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2253 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002254 goto unlock;
2255 }
2256
2257 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002258 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002259 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002260 goto unlock;
2261 }
2262
2263 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002264
Johan Hedbergb5235a62012-02-21 14:32:24 +02002265unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002266 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002267 return err;
2268}
2269
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002270static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002271 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002272{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002273 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002274 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2275 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002276 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002277 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002278 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002279
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002280 BT_DBG("request for %s", hdev->name);
2281
2282 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002283 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2284 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002285
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002286 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002287 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002288 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2289 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002290 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2291 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002292 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002293
Johan Hedberg86742e12011-11-07 23:13:38 +02002294 expected_len = sizeof(*cp) + key_count *
2295 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002296 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002297 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2298 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002299 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2300 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002301 }
2302
Johan Hedberg4ae14302013-01-20 14:27:13 +02002303 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002304 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2305 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002307 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002308 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002309
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002310 for (i = 0; i < key_count; i++) {
2311 struct mgmt_link_key_info *key = &cp->keys[i];
2312
Marcel Holtmann8e991132014-01-10 02:07:25 -08002313 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002314 return mgmt_cmd_status(sk, hdev->id,
2315 MGMT_OP_LOAD_LINK_KEYS,
2316 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002317 }
2318
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002319 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002320
2321 hci_link_keys_clear(hdev);
2322
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002323 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002324 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002325 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002326 changed = hci_dev_test_and_clear_flag(hdev,
2327 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002328
2329 if (changed)
2330 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002331
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002332 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002333 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002334
Johan Hedberg58e92932014-06-24 14:00:26 +03002335 /* Always ignore debug keys and require a new pairing if
2336 * the user wants to use them.
2337 */
2338 if (key->type == HCI_LK_DEBUG_COMBINATION)
2339 continue;
2340
Johan Hedberg7652ff62014-06-24 13:15:49 +03002341 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2342 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002343 }
2344
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002345 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002346
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002347 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002348
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002349 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002350}
2351
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002352static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002354{
2355 struct mgmt_ev_device_unpaired ev;
2356
2357 bacpy(&ev.addr.bdaddr, bdaddr);
2358 ev.addr.type = addr_type;
2359
2360 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002362}
2363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002364static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002365 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002366{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002367 struct mgmt_cp_unpair_device *cp = data;
2368 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002369 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002370 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002371 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002372 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002373 int err;
2374
Johan Hedberga8a1d192011-11-10 15:54:38 +02002375 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002376 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2377 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002378
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002379 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002380 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2381 MGMT_STATUS_INVALID_PARAMS,
2382 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002383
Johan Hedberg118da702013-01-20 14:27:20 +02002384 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002385 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2386 MGMT_STATUS_INVALID_PARAMS,
2387 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002388
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002389 hci_dev_lock(hdev);
2390
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002391 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002392 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2393 MGMT_STATUS_NOT_POWERED, &rp,
2394 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002395 goto unlock;
2396 }
2397
Johan Hedberge0b2b272014-02-18 17:14:31 +02002398 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002399 /* If disconnection is requested, then look up the
2400 * connection. If the remote device is connected, it
2401 * will be later used to terminate the link.
2402 *
2403 * Setting it to NULL explicitly will cause no
2404 * termination of the link.
2405 */
2406 if (cp->disconnect)
2407 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2408 &cp->addr.bdaddr);
2409 else
2410 conn = NULL;
2411
Johan Hedberg124f6e32012-02-09 13:50:12 +02002412 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002413 if (err < 0) {
2414 err = mgmt_cmd_complete(sk, hdev->id,
2415 MGMT_OP_UNPAIR_DEVICE,
2416 MGMT_STATUS_NOT_PAIRED, &rp,
2417 sizeof(rp));
2418 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002419 }
2420
Johan Hedbergec182f02015-10-21 18:03:03 +03002421 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002422 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002423
Johan Hedbergec182f02015-10-21 18:03:03 +03002424 /* LE address type */
2425 addr_type = le_addr_type(cp->addr.type);
2426
2427 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2428
2429 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002430 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002431 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2432 MGMT_STATUS_NOT_PAIRED, &rp,
2433 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002434 goto unlock;
2435 }
2436
Johan Hedbergec182f02015-10-21 18:03:03 +03002437 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2438 if (!conn) {
2439 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2440 goto done;
2441 }
2442
Johan Hedbergc81d5552015-10-22 09:38:35 +03002443 /* Abort any ongoing SMP pairing */
2444 smp_cancel_pairing(conn);
2445
Johan Hedbergec182f02015-10-21 18:03:03 +03002446 /* Defer clearing up the connection parameters until closing to
2447 * give a chance of keeping them if a repairing happens.
2448 */
2449 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2450
Johan Hedbergfc643612015-10-22 09:38:31 +03002451 /* Disable auto-connection parameters if present */
2452 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2453 if (params) {
2454 if (params->explicit_connect)
2455 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2456 else
2457 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2458 }
2459
Johan Hedbergec182f02015-10-21 18:03:03 +03002460 /* If disconnection is not requested, then clear the connection
2461 * variable so that the link is not terminated.
2462 */
2463 if (!cp->disconnect)
2464 conn = NULL;
2465
2466done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002467 /* If the connection variable is set, then termination of the
2468 * link is requested.
2469 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002470 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002471 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2472 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002473 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002474 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002475 }
2476
Johan Hedberg124f6e32012-02-09 13:50:12 +02002477 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002478 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002479 if (!cmd) {
2480 err = -ENOMEM;
2481 goto unlock;
2482 }
2483
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002484 cmd->cmd_complete = addr_cmd_complete;
2485
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002486 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002487 if (err < 0)
2488 mgmt_pending_remove(cmd);
2489
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002490unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002491 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002492 return err;
2493}
2494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002496 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002497{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002498 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002499 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002500 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002501 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002502 int err;
2503
2504 BT_DBG("");
2505
Johan Hedberg06a63b12013-01-20 14:27:21 +02002506 memset(&rp, 0, sizeof(rp));
2507 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2508 rp.addr.type = cp->addr.type;
2509
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002510 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002511 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2512 MGMT_STATUS_INVALID_PARAMS,
2513 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002515 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002516
2517 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002518 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2519 MGMT_STATUS_NOT_POWERED, &rp,
2520 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002521 goto failed;
2522 }
2523
Johan Hedberg333ae952015-03-17 13:48:47 +02002524 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002525 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2526 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002527 goto failed;
2528 }
2529
Andre Guedes591f47f2012-04-24 21:02:49 -03002530 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002531 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2532 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002533 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002534 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2535 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002536
Vishal Agarwalf9607272012-06-13 05:32:43 +05302537 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002538 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2539 MGMT_STATUS_NOT_CONNECTED, &rp,
2540 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002541 goto failed;
2542 }
2543
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002544 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002545 if (!cmd) {
2546 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002547 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002548 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002549
Johan Hedbergf5818c22014-12-05 13:36:02 +02002550 cmd->cmd_complete = generic_cmd_complete;
2551
Johan Hedberge3f2f922014-08-18 20:33:33 +03002552 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002553 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002554 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002555
2556failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002557 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002558 return err;
2559}
2560
Andre Guedes57c14772012-04-24 21:02:50 -03002561static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002562{
2563 switch (link_type) {
2564 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002565 switch (addr_type) {
2566 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002567 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002568
Johan Hedberg48264f02011-11-09 13:58:58 +02002569 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002570 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002571 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002572 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002573
Johan Hedberg4c659c32011-11-07 23:13:39 +02002574 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002575 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002576 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002577 }
2578}
2579
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2581 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002582{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002583 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002584 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002585 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002586 int err;
2587 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002588
2589 BT_DBG("");
2590
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002591 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002592
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002593 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002594 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2595 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002596 goto unlock;
2597 }
2598
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002599 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002600 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2601 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002602 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002603 }
2604
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002605 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002606 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002607 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002608 err = -ENOMEM;
2609 goto unlock;
2610 }
2611
Johan Hedberg2784eb42011-01-21 13:56:35 +02002612 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002613 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002614 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2615 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002616 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002617 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002618 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002619 continue;
2620 i++;
2621 }
2622
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002623 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002624
Johan Hedberg4c659c32011-11-07 23:13:39 +02002625 /* Recalculate length in case of filtered SCO connections, etc */
2626 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002627
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002628 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2629 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002630
Johan Hedberga38528f2011-01-22 06:46:43 +02002631 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002632
2633unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002634 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002635 return err;
2636}
2637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002638static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002639 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002640{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002641 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002642 int err;
2643
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002644 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002646 if (!cmd)
2647 return -ENOMEM;
2648
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002649 cmd->cmd_complete = addr_cmd_complete;
2650
Johan Hedbergd8457692012-02-17 14:24:57 +02002651 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002652 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002653 if (err < 0)
2654 mgmt_pending_remove(cmd);
2655
2656 return err;
2657}
2658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002659static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002660 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002661{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002662 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002663 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002664 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002665 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002666 int err;
2667
2668 BT_DBG("");
2669
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002670 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002671
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002672 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002673 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2674 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002675 goto failed;
2676 }
2677
Johan Hedbergd8457692012-02-17 14:24:57 +02002678 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002679 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002680 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2681 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002682 goto failed;
2683 }
2684
2685 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002686 struct mgmt_cp_pin_code_neg_reply ncp;
2687
2688 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002689
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002690 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002691
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002693 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002694 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2695 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002696
2697 goto failed;
2698 }
2699
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002700 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002701 if (!cmd) {
2702 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002703 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002704 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002705
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002706 cmd->cmd_complete = addr_cmd_complete;
2707
Johan Hedbergd8457692012-02-17 14:24:57 +02002708 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002709 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002710 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711
2712 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2713 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002714 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715
2716failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002717 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718 return err;
2719}
2720
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002721static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2722 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002723{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002724 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002725
2726 BT_DBG("");
2727
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002728 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002729 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002732 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002733
2734 hdev->io_capability = cp->io_capability;
2735
2736 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002737 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002739 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002740
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002741 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2742 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002743}
2744
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002745static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002746{
2747 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002748 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002749
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002750 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002751 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2752 continue;
2753
Johan Hedberge9a416b2011-02-19 12:05:56 -03002754 if (cmd->user_data != conn)
2755 continue;
2756
2757 return cmd;
2758 }
2759
2760 return NULL;
2761}
2762
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002763static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002764{
2765 struct mgmt_rp_pair_device rp;
2766 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002767 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002768
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002769 bacpy(&rp.addr.bdaddr, &conn->dst);
2770 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002771
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002772 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2773 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002774
2775 /* So we don't get further callbacks for this connection */
2776 conn->connect_cfm_cb = NULL;
2777 conn->security_cfm_cb = NULL;
2778 conn->disconn_cfm_cb = NULL;
2779
David Herrmann76a68ba2013-04-06 20:28:37 +02002780 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002781
2782 /* The device is paired so there is no need to remove
2783 * its connection parameters anymore.
2784 */
2785 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002786
2787 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002788
2789 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002790}
2791
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002792void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2793{
2794 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002795 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002796
2797 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002798 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002799 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002800 mgmt_pending_remove(cmd);
2801 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002802}
2803
Johan Hedberge9a416b2011-02-19 12:05:56 -03002804static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2805{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002806 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002807
2808 BT_DBG("status %u", status);
2809
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002810 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002811 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002812 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002813 return;
2814 }
2815
2816 cmd->cmd_complete(cmd, mgmt_status(status));
2817 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002818}
2819
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002820static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302821{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002822 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302823
2824 BT_DBG("status %u", status);
2825
2826 if (!status)
2827 return;
2828
2829 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002830 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302831 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002832 return;
2833 }
2834
2835 cmd->cmd_complete(cmd, mgmt_status(status));
2836 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302837}
2838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002839static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002840 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002841{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002842 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002843 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002844 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002845 u8 sec_level, auth_type;
2846 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002847 int err;
2848
2849 BT_DBG("");
2850
Szymon Jancf950a30e2013-01-18 12:48:07 +01002851 memset(&rp, 0, sizeof(rp));
2852 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2853 rp.addr.type = cp->addr.type;
2854
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002855 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002856 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2857 MGMT_STATUS_INVALID_PARAMS,
2858 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002859
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002860 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002861 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2862 MGMT_STATUS_INVALID_PARAMS,
2863 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002864
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002865 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002866
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002867 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002868 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2869 MGMT_STATUS_NOT_POWERED, &rp,
2870 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002871 goto unlock;
2872 }
2873
Johan Hedberg55e76b32015-03-10 22:34:40 +02002874 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2875 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2876 MGMT_STATUS_ALREADY_PAIRED, &rp,
2877 sizeof(rp));
2878 goto unlock;
2879 }
2880
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002881 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002882 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002883
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002884 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002885 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2886 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002887 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002888 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002889 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002890
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002891 /* When pairing a new device, it is expected to remember
2892 * this device for future connections. Adding the connection
2893 * parameter information ahead of time allows tracking
2894 * of the slave preferred values and will speed up any
2895 * further connection establishment.
2896 *
2897 * If connection parameters already exist, then they
2898 * will be kept and this function does nothing.
2899 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002900 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2901
2902 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2903 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002904
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002905 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2906 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002907 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002908 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002909
Ville Tervo30e76272011-02-22 16:10:53 -03002910 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002911 int status;
2912
2913 if (PTR_ERR(conn) == -EBUSY)
2914 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002915 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2916 status = MGMT_STATUS_NOT_SUPPORTED;
2917 else if (PTR_ERR(conn) == -ECONNREFUSED)
2918 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002919 else
2920 status = MGMT_STATUS_CONNECT_FAILED;
2921
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002922 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2923 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002924 goto unlock;
2925 }
2926
2927 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002928 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002929 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2930 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002931 goto unlock;
2932 }
2933
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002934 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002935 if (!cmd) {
2936 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002937 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002938 goto unlock;
2939 }
2940
Johan Hedberg04ab2742014-12-05 13:36:04 +02002941 cmd->cmd_complete = pairing_complete;
2942
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002943 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002944 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002945 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002946 conn->security_cfm_cb = pairing_complete_cb;
2947 conn->disconn_cfm_cb = pairing_complete_cb;
2948 } else {
2949 conn->connect_cfm_cb = le_pairing_complete_cb;
2950 conn->security_cfm_cb = le_pairing_complete_cb;
2951 conn->disconn_cfm_cb = le_pairing_complete_cb;
2952 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002953
Johan Hedberge9a416b2011-02-19 12:05:56 -03002954 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002955 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002956
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002957 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002958 hci_conn_security(conn, sec_level, auth_type, true)) {
2959 cmd->cmd_complete(cmd, 0);
2960 mgmt_pending_remove(cmd);
2961 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002962
2963 err = 0;
2964
2965unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002966 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002967 return err;
2968}
2969
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002970static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2971 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002972{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002973 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002974 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002975 struct hci_conn *conn;
2976 int err;
2977
2978 BT_DBG("");
2979
Johan Hedberg28424702012-02-02 04:02:29 +02002980 hci_dev_lock(hdev);
2981
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002982 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002983 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2984 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002985 goto unlock;
2986 }
2987
Johan Hedberg333ae952015-03-17 13:48:47 +02002988 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002989 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002990 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2991 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002992 goto unlock;
2993 }
2994
2995 conn = cmd->user_data;
2996
2997 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002998 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2999 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003000 goto unlock;
3001 }
3002
Johan Hedberga511b352014-12-11 21:45:45 +02003003 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3004 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003005
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003006 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3007 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003008unlock:
3009 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003010 return err;
3011}
3012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003013static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003014 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003015 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003016{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003017 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003018 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003019 int err;
3020
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003021 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003022
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003023 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003024 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3025 MGMT_STATUS_NOT_POWERED, addr,
3026 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003027 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003028 }
3029
Johan Hedberg1707c602013-03-15 17:07:15 -05003030 if (addr->type == BDADDR_BREDR)
3031 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003032 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003033 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3034 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003035
Johan Hedberg272d90d2012-02-09 15:26:12 +02003036 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003037 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3038 MGMT_STATUS_NOT_CONNECTED, addr,
3039 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003040 goto done;
3041 }
3042
Johan Hedberg1707c602013-03-15 17:07:15 -05003043 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003044 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003045 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003046 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3047 MGMT_STATUS_SUCCESS, addr,
3048 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003049 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003050 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3051 MGMT_STATUS_FAILED, addr,
3052 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003053
Brian Gix47c15e22011-11-16 13:53:14 -08003054 goto done;
3055 }
3056
Johan Hedberg1707c602013-03-15 17:07:15 -05003057 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003058 if (!cmd) {
3059 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003060 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003061 }
3062
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003063 cmd->cmd_complete = addr_cmd_complete;
3064
Brian Gix0df4c182011-11-16 13:53:13 -08003065 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003066 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3067 struct hci_cp_user_passkey_reply cp;
3068
Johan Hedberg1707c602013-03-15 17:07:15 -05003069 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003070 cp.passkey = passkey;
3071 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3072 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003073 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3074 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003075
Johan Hedberga664b5b2011-02-19 12:06:02 -03003076 if (err < 0)
3077 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003078
Brian Gix0df4c182011-11-16 13:53:13 -08003079done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003080 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003081 return err;
3082}
3083
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303084static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3085 void *data, u16 len)
3086{
3087 struct mgmt_cp_pin_code_neg_reply *cp = data;
3088
3089 BT_DBG("");
3090
Johan Hedberg1707c602013-03-15 17:07:15 -05003091 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303092 MGMT_OP_PIN_CODE_NEG_REPLY,
3093 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3094}
3095
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003096static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3097 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003098{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003099 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003100
3101 BT_DBG("");
3102
3103 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003104 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3105 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003106
Johan Hedberg1707c602013-03-15 17:07:15 -05003107 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003108 MGMT_OP_USER_CONFIRM_REPLY,
3109 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003110}
3111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003112static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003113 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003114{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003115 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003116
3117 BT_DBG("");
3118
Johan Hedberg1707c602013-03-15 17:07:15 -05003119 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003120 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3121 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003122}
3123
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003124static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3125 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003126{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003127 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003128
3129 BT_DBG("");
3130
Johan Hedberg1707c602013-03-15 17:07:15 -05003131 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132 MGMT_OP_USER_PASSKEY_REPLY,
3133 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003134}
3135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003136static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003137 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003138{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003139 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003140
3141 BT_DBG("");
3142
Johan Hedberg1707c602013-03-15 17:07:15 -05003143 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3145 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003146}
3147
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003148static void adv_expire(struct hci_dev *hdev, u32 flags)
3149{
3150 struct adv_info *adv_instance;
3151 struct hci_request req;
3152 int err;
3153
3154 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3155 if (!adv_instance)
3156 return;
3157
3158 /* stop if current instance doesn't need to be changed */
3159 if (!(adv_instance->flags & flags))
3160 return;
3161
3162 cancel_adv_timeout(hdev);
3163
3164 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3165 if (!adv_instance)
3166 return;
3167
3168 hci_req_init(&req, hdev);
3169 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3170 true);
3171 if (err)
3172 return;
3173
3174 hci_req_run(&req, NULL);
3175}
3176
Marcel Holtmann1904a852015-01-11 13:50:44 -08003177static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003178{
3179 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003180 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003181
3182 BT_DBG("status 0x%02x", status);
3183
3184 hci_dev_lock(hdev);
3185
Johan Hedberg333ae952015-03-17 13:48:47 +02003186 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003187 if (!cmd)
3188 goto unlock;
3189
3190 cp = cmd->param;
3191
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003192 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003193 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3194 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003195 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003196 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3197 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003198
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003199 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3200 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3201 }
3202
Johan Hedberg13928972013-03-15 17:07:00 -05003203 mgmt_pending_remove(cmd);
3204
3205unlock:
3206 hci_dev_unlock(hdev);
3207}
3208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003209static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003210 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003211{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003212 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003213 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003214 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003215 int err;
3216
3217 BT_DBG("");
3218
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003219 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003220
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003221 /* If the old values are the same as the new ones just return a
3222 * direct command complete event.
3223 */
3224 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3225 !memcmp(hdev->short_name, cp->short_name,
3226 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003227 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3228 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003229 goto failed;
3230 }
3231
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003232 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003233
Johan Hedbergb5235a62012-02-21 14:32:24 +02003234 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003235 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003236
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003237 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3238 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003239 if (err < 0)
3240 goto failed;
3241
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003242 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3243 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003244 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003245
Johan Hedbergb5235a62012-02-21 14:32:24 +02003246 goto failed;
3247 }
3248
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003249 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003250 if (!cmd) {
3251 err = -ENOMEM;
3252 goto failed;
3253 }
3254
Johan Hedberg13928972013-03-15 17:07:00 -05003255 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3256
Johan Hedberg890ea892013-03-15 17:06:52 -05003257 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003258
3259 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003260 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003261 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003262 }
3263
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003264 /* The name is stored in the scan response data and so
3265 * no need to udpate the advertising data here.
3266 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003267 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003268 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003269
Johan Hedberg13928972013-03-15 17:07:00 -05003270 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003271 if (err < 0)
3272 mgmt_pending_remove(cmd);
3273
3274failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003275 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003276 return err;
3277}
3278
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003279static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3280 u16 len)
3281{
3282 struct mgmt_cp_set_appearance *cp = data;
3283 u16 apperance;
3284 int err;
3285
3286 BT_DBG("");
3287
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003288 if (!lmp_le_capable(hdev))
3289 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3290 MGMT_STATUS_NOT_SUPPORTED);
3291
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003292 apperance = le16_to_cpu(cp->appearance);
3293
3294 hci_dev_lock(hdev);
3295
3296 if (hdev->appearance != apperance) {
3297 hdev->appearance = apperance;
3298
3299 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3300 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003301
3302 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003303 }
3304
3305 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3306 0);
3307
3308 hci_dev_unlock(hdev);
3309
3310 return err;
3311}
3312
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303313static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3314 void *data, u16 len)
3315{
3316 struct mgmt_rp_get_phy_confguration rp;
3317
3318 BT_DBG("sock %p %s", sk, hdev->name);
3319
3320 hci_dev_lock(hdev);
3321
3322 memset(&rp, 0, sizeof(rp));
3323
3324 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3325 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3326 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3327
3328 hci_dev_unlock(hdev);
3329
3330 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3331 &rp, sizeof(rp));
3332}
3333
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303334int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3335{
3336 struct mgmt_ev_phy_configuration_changed ev;
3337
3338 memset(&ev, 0, sizeof(ev));
3339
3340 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3341
3342 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3343 sizeof(ev), skip);
3344}
3345
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303346static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3347 u16 opcode, struct sk_buff *skb)
3348{
3349 struct mgmt_cp_set_phy_confguration *cp;
3350 struct mgmt_pending_cmd *cmd;
3351
3352 BT_DBG("status 0x%02x", status);
3353
3354 hci_dev_lock(hdev);
3355
3356 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3357 if (!cmd)
3358 goto unlock;
3359
3360 cp = cmd->param;
3361
3362 if (status) {
3363 mgmt_cmd_status(cmd->sk, hdev->id,
3364 MGMT_OP_SET_PHY_CONFIGURATION,
3365 mgmt_status(status));
3366 } else {
3367 mgmt_cmd_complete(cmd->sk, hdev->id,
3368 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3369 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303370
3371 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303372 }
3373
3374 mgmt_pending_remove(cmd);
3375
3376unlock:
3377 hci_dev_unlock(hdev);
3378}
3379
3380static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3381 void *data, u16 len)
3382{
3383 struct mgmt_cp_set_phy_confguration *cp = data;
3384 struct hci_cp_le_set_default_phy cp_phy;
3385 struct mgmt_pending_cmd *cmd;
3386 struct hci_request req;
3387 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3388 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303389 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303390 int err;
3391
3392 BT_DBG("sock %p %s", sk, hdev->name);
3393
3394 configurable_phys = get_configurable_phys(hdev);
3395 supported_phys = get_supported_phys(hdev);
3396 selected_phys = __le32_to_cpu(cp->selected_phys);
3397
3398 if (selected_phys & ~supported_phys)
3399 return mgmt_cmd_status(sk, hdev->id,
3400 MGMT_OP_SET_PHY_CONFIGURATION,
3401 MGMT_STATUS_INVALID_PARAMS);
3402
3403 unconfigure_phys = supported_phys & ~configurable_phys;
3404
3405 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3406 return mgmt_cmd_status(sk, hdev->id,
3407 MGMT_OP_SET_PHY_CONFIGURATION,
3408 MGMT_STATUS_INVALID_PARAMS);
3409
3410 if (selected_phys == get_selected_phys(hdev))
3411 return mgmt_cmd_complete(sk, hdev->id,
3412 MGMT_OP_SET_PHY_CONFIGURATION,
3413 0, NULL, 0);
3414
3415 hci_dev_lock(hdev);
3416
3417 if (!hdev_is_powered(hdev)) {
3418 err = mgmt_cmd_status(sk, hdev->id,
3419 MGMT_OP_SET_PHY_CONFIGURATION,
3420 MGMT_STATUS_REJECTED);
3421 goto unlock;
3422 }
3423
3424 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3425 err = mgmt_cmd_status(sk, hdev->id,
3426 MGMT_OP_SET_PHY_CONFIGURATION,
3427 MGMT_STATUS_BUSY);
3428 goto unlock;
3429 }
3430
3431 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3432 pkt_type |= (HCI_DH3 | HCI_DM3);
3433 else
3434 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3435
3436 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3437 pkt_type |= (HCI_DH5 | HCI_DM5);
3438 else
3439 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3440
3441 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3442 pkt_type &= ~HCI_2DH1;
3443 else
3444 pkt_type |= HCI_2DH1;
3445
3446 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3447 pkt_type &= ~HCI_2DH3;
3448 else
3449 pkt_type |= HCI_2DH3;
3450
3451 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3452 pkt_type &= ~HCI_2DH5;
3453 else
3454 pkt_type |= HCI_2DH5;
3455
3456 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3457 pkt_type &= ~HCI_3DH1;
3458 else
3459 pkt_type |= HCI_3DH1;
3460
3461 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3462 pkt_type &= ~HCI_3DH3;
3463 else
3464 pkt_type |= HCI_3DH3;
3465
3466 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3467 pkt_type &= ~HCI_3DH5;
3468 else
3469 pkt_type |= HCI_3DH5;
3470
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303471 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303472 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303473 changed = true;
3474 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303475
3476 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3477 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303478 if (changed)
3479 mgmt_phy_configuration_changed(hdev, sk);
3480
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303481 err = mgmt_cmd_complete(sk, hdev->id,
3482 MGMT_OP_SET_PHY_CONFIGURATION,
3483 0, NULL, 0);
3484
3485 goto unlock;
3486 }
3487
3488 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3489 len);
3490 if (!cmd) {
3491 err = -ENOMEM;
3492 goto unlock;
3493 }
3494
3495 hci_req_init(&req, hdev);
3496
3497 memset(&cp_phy, 0, sizeof(cp_phy));
3498
3499 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3500 cp_phy.all_phys |= 0x01;
3501
3502 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3503 cp_phy.all_phys |= 0x02;
3504
3505 if (selected_phys & MGMT_PHY_LE_1M_TX)
3506 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3507
3508 if (selected_phys & MGMT_PHY_LE_2M_TX)
3509 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3510
3511 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3512 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3513
3514 if (selected_phys & MGMT_PHY_LE_1M_RX)
3515 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3516
3517 if (selected_phys & MGMT_PHY_LE_2M_RX)
3518 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3519
3520 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3521 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3522
3523 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3524
3525 err = hci_req_run_skb(&req, set_default_phy_complete);
3526 if (err < 0)
3527 mgmt_pending_remove(cmd);
3528
3529unlock:
3530 hci_dev_unlock(hdev);
3531
3532 return err;
3533}
3534
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003535static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3536 u16 opcode, struct sk_buff *skb)
3537{
3538 struct mgmt_rp_read_local_oob_data mgmt_rp;
3539 size_t rp_size = sizeof(mgmt_rp);
3540 struct mgmt_pending_cmd *cmd;
3541
3542 BT_DBG("%s status %u", hdev->name, status);
3543
3544 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3545 if (!cmd)
3546 return;
3547
3548 if (status || !skb) {
3549 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3550 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3551 goto remove;
3552 }
3553
3554 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3555
3556 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3557 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3558
3559 if (skb->len < sizeof(*rp)) {
3560 mgmt_cmd_status(cmd->sk, hdev->id,
3561 MGMT_OP_READ_LOCAL_OOB_DATA,
3562 MGMT_STATUS_FAILED);
3563 goto remove;
3564 }
3565
3566 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3567 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3568
3569 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3570 } else {
3571 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3572
3573 if (skb->len < sizeof(*rp)) {
3574 mgmt_cmd_status(cmd->sk, hdev->id,
3575 MGMT_OP_READ_LOCAL_OOB_DATA,
3576 MGMT_STATUS_FAILED);
3577 goto remove;
3578 }
3579
3580 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3581 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3582
3583 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3584 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3585 }
3586
3587 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3588 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3589
3590remove:
3591 mgmt_pending_remove(cmd);
3592}
3593
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003594static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003595 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003596{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003597 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003598 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003599 int err;
3600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003601 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003602
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003603 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003604
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003605 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003606 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3607 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003608 goto unlock;
3609 }
3610
Andre Guedes9a1a1992012-07-24 15:03:48 -03003611 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003612 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3613 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003614 goto unlock;
3615 }
3616
Johan Hedberg333ae952015-03-17 13:48:47 +02003617 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003618 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3619 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003620 goto unlock;
3621 }
3622
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003623 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003624 if (!cmd) {
3625 err = -ENOMEM;
3626 goto unlock;
3627 }
3628
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003629 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003630
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003631 if (bredr_sc_enabled(hdev))
3632 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3633 else
3634 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3635
3636 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003637 if (err < 0)
3638 mgmt_pending_remove(cmd);
3639
3640unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003641 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003642 return err;
3643}
3644
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003645static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003646 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003647{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003648 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003649 int err;
3650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003651 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003652
Johan Hedberg5d57e792015-01-23 10:10:38 +02003653 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003654 return mgmt_cmd_complete(sk, hdev->id,
3655 MGMT_OP_ADD_REMOTE_OOB_DATA,
3656 MGMT_STATUS_INVALID_PARAMS,
3657 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003659 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003660
Marcel Holtmannec109112014-01-10 02:07:30 -08003661 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3662 struct mgmt_cp_add_remote_oob_data *cp = data;
3663 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003664
Johan Hedbergc19a4952014-11-17 20:52:19 +02003665 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003666 err = mgmt_cmd_complete(sk, hdev->id,
3667 MGMT_OP_ADD_REMOTE_OOB_DATA,
3668 MGMT_STATUS_INVALID_PARAMS,
3669 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003670 goto unlock;
3671 }
3672
Marcel Holtmannec109112014-01-10 02:07:30 -08003673 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003674 cp->addr.type, cp->hash,
3675 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003676 if (err < 0)
3677 status = MGMT_STATUS_FAILED;
3678 else
3679 status = MGMT_STATUS_SUCCESS;
3680
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003681 err = mgmt_cmd_complete(sk, hdev->id,
3682 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3683 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003684 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3685 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003686 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003687 u8 status;
3688
Johan Hedberg86df9202014-10-26 20:52:27 +01003689 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003690 /* Enforce zero-valued 192-bit parameters as
3691 * long as legacy SMP OOB isn't implemented.
3692 */
3693 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3694 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003695 err = mgmt_cmd_complete(sk, hdev->id,
3696 MGMT_OP_ADD_REMOTE_OOB_DATA,
3697 MGMT_STATUS_INVALID_PARAMS,
3698 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003699 goto unlock;
3700 }
3701
Johan Hedberg86df9202014-10-26 20:52:27 +01003702 rand192 = NULL;
3703 hash192 = NULL;
3704 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003705 /* In case one of the P-192 values is set to zero,
3706 * then just disable OOB data for P-192.
3707 */
3708 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3709 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3710 rand192 = NULL;
3711 hash192 = NULL;
3712 } else {
3713 rand192 = cp->rand192;
3714 hash192 = cp->hash192;
3715 }
3716 }
3717
3718 /* In case one of the P-256 values is set to zero, then just
3719 * disable OOB data for P-256.
3720 */
3721 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3722 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3723 rand256 = NULL;
3724 hash256 = NULL;
3725 } else {
3726 rand256 = cp->rand256;
3727 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003728 }
3729
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003730 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003731 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003732 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003733 if (err < 0)
3734 status = MGMT_STATUS_FAILED;
3735 else
3736 status = MGMT_STATUS_SUCCESS;
3737
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003738 err = mgmt_cmd_complete(sk, hdev->id,
3739 MGMT_OP_ADD_REMOTE_OOB_DATA,
3740 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003741 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003742 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
3743 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003744 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3745 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003746 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003747
Johan Hedbergc19a4952014-11-17 20:52:19 +02003748unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003749 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003750 return err;
3751}
3752
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003753static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003754 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003755{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003756 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003757 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003758 int err;
3759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003760 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003761
Johan Hedbergc19a4952014-11-17 20:52:19 +02003762 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003763 return mgmt_cmd_complete(sk, hdev->id,
3764 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3765 MGMT_STATUS_INVALID_PARAMS,
3766 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003767
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003768 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003769
Johan Hedbergeedbd582014-11-15 09:34:23 +02003770 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3771 hci_remote_oob_data_clear(hdev);
3772 status = MGMT_STATUS_SUCCESS;
3773 goto done;
3774 }
3775
Johan Hedberg6928a922014-10-26 20:46:09 +01003776 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003777 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003778 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003779 else
Szymon Janca6785be2012-12-13 15:11:21 +01003780 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003781
Johan Hedbergeedbd582014-11-15 09:34:23 +02003782done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003783 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3784 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003785
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003786 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003787 return err;
3788}
3789
Johan Hedberge68f0722015-11-11 08:30:30 +02003790void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003791{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003792 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003793
Andre Guedes7c307722013-04-30 15:29:28 -03003794 BT_DBG("status %d", status);
3795
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003796 hci_dev_lock(hdev);
3797
Johan Hedberg333ae952015-03-17 13:48:47 +02003798 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003799 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003800 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003801
Johan Hedberg78b781c2016-01-05 13:19:32 +02003802 if (!cmd)
3803 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3804
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003805 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003806 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003807 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003808 }
3809
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003810 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003811}
3812
Johan Hedberg591752a2015-11-11 08:11:24 +02003813static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3814 uint8_t *mgmt_status)
3815{
3816 switch (type) {
3817 case DISCOV_TYPE_LE:
3818 *mgmt_status = mgmt_le_support(hdev);
3819 if (*mgmt_status)
3820 return false;
3821 break;
3822 case DISCOV_TYPE_INTERLEAVED:
3823 *mgmt_status = mgmt_le_support(hdev);
3824 if (*mgmt_status)
3825 return false;
3826 /* Intentional fall-through */
3827 case DISCOV_TYPE_BREDR:
3828 *mgmt_status = mgmt_bredr_support(hdev);
3829 if (*mgmt_status)
3830 return false;
3831 break;
3832 default:
3833 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3834 return false;
3835 }
3836
3837 return true;
3838}
3839
Johan Hedberg78b781c2016-01-05 13:19:32 +02003840static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3841 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003843 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003844 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003845 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003846 int err;
3847
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003848 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003849
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003850 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003851
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003852 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003853 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003854 MGMT_STATUS_NOT_POWERED,
3855 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003856 goto failed;
3857 }
3858
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003859 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003860 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003861 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3862 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003863 goto failed;
3864 }
3865
Johan Hedberg591752a2015-11-11 08:11:24 +02003866 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003867 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3868 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003869 goto failed;
3870 }
3871
Marcel Holtmann22078802014-12-05 11:45:22 +01003872 /* Clear the discovery filter first to free any previously
3873 * allocated memory for the UUID list.
3874 */
3875 hci_discovery_filter_clear(hdev);
3876
Andre Guedes4aab14e2012-02-17 20:39:36 -03003877 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003878 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003879 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3880 hdev->discovery.limited = true;
3881 else
3882 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003883
Johan Hedberg78b781c2016-01-05 13:19:32 +02003884 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003885 if (!cmd) {
3886 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003887 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003888 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003889
Johan Hedberge68f0722015-11-11 08:30:30 +02003890 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003891
3892 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003893 queue_work(hdev->req_workqueue, &hdev->discov_update);
3894 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003895
3896failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003897 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003898 return err;
3899}
3900
Johan Hedberg78b781c2016-01-05 13:19:32 +02003901static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3902 void *data, u16 len)
3903{
3904 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3905 data, len);
3906}
3907
3908static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3909 void *data, u16 len)
3910{
3911 return start_discovery_internal(sk, hdev,
3912 MGMT_OP_START_LIMITED_DISCOVERY,
3913 data, len);
3914}
3915
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003916static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3917 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003918{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003919 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3920 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003921}
3922
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003923static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3924 void *data, u16 len)
3925{
3926 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003927 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003928 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3929 u16 uuid_count, expected_len;
3930 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003931 int err;
3932
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003933 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003934
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003935 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003936
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003937 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003938 err = mgmt_cmd_complete(sk, hdev->id,
3939 MGMT_OP_START_SERVICE_DISCOVERY,
3940 MGMT_STATUS_NOT_POWERED,
3941 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003942 goto failed;
3943 }
3944
3945 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003946 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003947 err = mgmt_cmd_complete(sk, hdev->id,
3948 MGMT_OP_START_SERVICE_DISCOVERY,
3949 MGMT_STATUS_BUSY, &cp->type,
3950 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003951 goto failed;
3952 }
3953
3954 uuid_count = __le16_to_cpu(cp->uuid_count);
3955 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003956 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
3957 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003958 err = mgmt_cmd_complete(sk, hdev->id,
3959 MGMT_OP_START_SERVICE_DISCOVERY,
3960 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3961 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003962 goto failed;
3963 }
3964
3965 expected_len = sizeof(*cp) + uuid_count * 16;
3966 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003967 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
3968 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003969 err = mgmt_cmd_complete(sk, hdev->id,
3970 MGMT_OP_START_SERVICE_DISCOVERY,
3971 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3972 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003973 goto failed;
3974 }
3975
Johan Hedberg591752a2015-11-11 08:11:24 +02003976 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3977 err = mgmt_cmd_complete(sk, hdev->id,
3978 MGMT_OP_START_SERVICE_DISCOVERY,
3979 status, &cp->type, sizeof(cp->type));
3980 goto failed;
3981 }
3982
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003983 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003984 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003985 if (!cmd) {
3986 err = -ENOMEM;
3987 goto failed;
3988 }
3989
Johan Hedberg2922a942014-12-05 13:36:06 +02003990 cmd->cmd_complete = service_discovery_cmd_complete;
3991
Marcel Holtmann22078802014-12-05 11:45:22 +01003992 /* Clear the discovery filter first to free any previously
3993 * allocated memory for the UUID list.
3994 */
3995 hci_discovery_filter_clear(hdev);
3996
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003997 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003998 hdev->discovery.type = cp->type;
3999 hdev->discovery.rssi = cp->rssi;
4000 hdev->discovery.uuid_count = uuid_count;
4001
4002 if (uuid_count > 0) {
4003 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4004 GFP_KERNEL);
4005 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004006 err = mgmt_cmd_complete(sk, hdev->id,
4007 MGMT_OP_START_SERVICE_DISCOVERY,
4008 MGMT_STATUS_FAILED,
4009 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004010 mgmt_pending_remove(cmd);
4011 goto failed;
4012 }
4013 }
4014
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004015 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004016 queue_work(hdev->req_workqueue, &hdev->discov_update);
4017 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004018
4019failed:
4020 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004021 return err;
4022}
4023
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004024void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004025{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004026 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004027
Andre Guedes0e05bba2013-04-30 15:29:33 -03004028 BT_DBG("status %d", status);
4029
4030 hci_dev_lock(hdev);
4031
Johan Hedberg333ae952015-03-17 13:48:47 +02004032 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004033 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004034 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004035 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004036 }
4037
Andre Guedes0e05bba2013-04-30 15:29:33 -03004038 hci_dev_unlock(hdev);
4039}
4040
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004041static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004042 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004043{
Johan Hedbergd9306502012-02-20 23:25:18 +02004044 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004045 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004046 int err;
4047
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004048 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004049
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004050 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004051
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004052 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004053 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4054 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4055 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004056 goto unlock;
4057 }
4058
4059 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004060 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4061 MGMT_STATUS_INVALID_PARAMS,
4062 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004063 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004064 }
4065
Johan Hedberg2922a942014-12-05 13:36:06 +02004066 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004067 if (!cmd) {
4068 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004069 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004070 }
4071
Johan Hedberg2922a942014-12-05 13:36:06 +02004072 cmd->cmd_complete = generic_cmd_complete;
4073
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004074 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4075 queue_work(hdev->req_workqueue, &hdev->discov_update);
4076 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004077
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004078unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004079 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004080 return err;
4081}
4082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004083static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004084 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004085{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004086 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004087 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004088 int err;
4089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004090 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004091
Johan Hedberg561aafb2012-01-04 13:31:59 +02004092 hci_dev_lock(hdev);
4093
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004094 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004095 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4096 MGMT_STATUS_FAILED, &cp->addr,
4097 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004098 goto failed;
4099 }
4100
Johan Hedberga198e7b2012-02-17 14:27:06 +02004101 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004102 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004103 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4104 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4105 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004106 goto failed;
4107 }
4108
4109 if (cp->name_known) {
4110 e->name_state = NAME_KNOWN;
4111 list_del(&e->list);
4112 } else {
4113 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004114 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004115 }
4116
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004117 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4118 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004119
4120failed:
4121 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004122 return err;
4123}
4124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004125static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004126 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004127{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004128 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004129 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004130 int err;
4131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004132 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004133
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004134 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004135 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4136 MGMT_STATUS_INVALID_PARAMS,
4137 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004138
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004139 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004140
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004141 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4142 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004143 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004144 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004145 goto done;
4146 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004147
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004148 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4149 sk);
4150 status = MGMT_STATUS_SUCCESS;
4151
4152done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004153 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4154 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004156 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004157
4158 return err;
4159}
4160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004161static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004162 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004163{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004164 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004165 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004166 int err;
4167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004168 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004169
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004170 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004171 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4172 MGMT_STATUS_INVALID_PARAMS,
4173 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004174
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004175 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004176
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004177 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4178 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004179 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004180 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004181 goto done;
4182 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004183
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004184 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4185 sk);
4186 status = MGMT_STATUS_SUCCESS;
4187
4188done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004189 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4190 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004191
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004192 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004193
4194 return err;
4195}
4196
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004197static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4198 u16 len)
4199{
4200 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004201 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004202 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004203 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004204
4205 BT_DBG("%s", hdev->name);
4206
Szymon Jancc72d4b82012-03-16 16:02:57 +01004207 source = __le16_to_cpu(cp->source);
4208
4209 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004210 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4211 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004212
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004213 hci_dev_lock(hdev);
4214
Szymon Jancc72d4b82012-03-16 16:02:57 +01004215 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004216 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4217 hdev->devid_product = __le16_to_cpu(cp->product);
4218 hdev->devid_version = __le16_to_cpu(cp->version);
4219
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004220 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4221 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004222
Johan Hedberg890ea892013-03-15 17:06:52 -05004223 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004224 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004225 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004226
4227 hci_dev_unlock(hdev);
4228
4229 return err;
4230}
4231
Arman Uguray24b4f382015-03-23 15:57:12 -07004232static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4233 u16 opcode)
4234{
4235 BT_DBG("status %d", status);
4236}
4237
Marcel Holtmann1904a852015-01-11 13:50:44 -08004238static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4239 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004240{
4241 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004242 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004243 u8 instance;
4244 struct adv_info *adv_instance;
4245 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004246
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304247 hci_dev_lock(hdev);
4248
Johan Hedberg4375f102013-09-25 13:26:10 +03004249 if (status) {
4250 u8 mgmt_err = mgmt_status(status);
4251
4252 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4253 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304254 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004255 }
4256
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004257 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004258 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004259 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004260 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004261
Johan Hedberg4375f102013-09-25 13:26:10 +03004262 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4263 &match);
4264
4265 new_settings(hdev, match.sk);
4266
4267 if (match.sk)
4268 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304269
Arman Uguray24b4f382015-03-23 15:57:12 -07004270 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004271 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004272 */
4273 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004274 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004275 goto unlock;
4276
Florian Grandel7816b822015-06-18 03:16:45 +02004277 instance = hdev->cur_adv_instance;
4278 if (!instance) {
4279 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4280 struct adv_info, list);
4281 if (!adv_instance)
4282 goto unlock;
4283
4284 instance = adv_instance->instance;
4285 }
4286
Arman Uguray24b4f382015-03-23 15:57:12 -07004287 hci_req_init(&req, hdev);
4288
Johan Hedbergf2252572015-11-18 12:49:20 +02004289 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004290
Florian Grandel7816b822015-06-18 03:16:45 +02004291 if (!err)
4292 err = hci_req_run(&req, enable_advertising_instance);
4293
4294 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004295 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004296
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304297unlock:
4298 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004299}
4300
Marcel Holtmann21b51872013-10-10 09:47:53 -07004301static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4302 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004303{
4304 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004305 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004306 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004307 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004308 int err;
4309
4310 BT_DBG("request for %s", hdev->name);
4311
Johan Hedberge6fe7982013-10-02 15:45:22 +03004312 status = mgmt_le_support(hdev);
4313 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4315 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004316
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004317 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004318 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4319 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004320
4321 hci_dev_lock(hdev);
4322
4323 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004324
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004325 /* The following conditions are ones which mean that we should
4326 * not do any HCI communication but directly send a mgmt
4327 * response to user space (after toggling the flag if
4328 * necessary).
4329 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004330 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004331 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4332 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004333 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004334 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004335 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004336 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004337
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004338 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004339 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004340 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004341 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004342 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004343 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004344 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004345 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004346 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004347 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004348 }
4349
4350 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4351 if (err < 0)
4352 goto unlock;
4353
4354 if (changed)
4355 err = new_settings(hdev, sk);
4356
4357 goto unlock;
4358 }
4359
Johan Hedberg333ae952015-03-17 13:48:47 +02004360 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4361 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004362 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4363 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004364 goto unlock;
4365 }
4366
4367 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4368 if (!cmd) {
4369 err = -ENOMEM;
4370 goto unlock;
4371 }
4372
4373 hci_req_init(&req, hdev);
4374
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004375 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004376 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004377 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004378 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004379
Florian Grandel7816b822015-06-18 03:16:45 +02004380 cancel_adv_timeout(hdev);
4381
Arman Uguray24b4f382015-03-23 15:57:12 -07004382 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004383 /* Switch to instance "0" for the Set Advertising setting.
4384 * We cannot use update_[adv|scan_rsp]_data() here as the
4385 * HCI_ADVERTISING flag is not yet set.
4386 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004387 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304388
4389 if (ext_adv_capable(hdev)) {
4390 __hci_req_start_ext_adv(&req, 0x00);
4391 } else {
4392 __hci_req_update_adv_data(&req, 0x00);
4393 __hci_req_update_scan_rsp_data(&req, 0x00);
4394 __hci_req_enable_advertising(&req);
4395 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004396 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004397 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004398 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004399
4400 err = hci_req_run(&req, set_advertising_complete);
4401 if (err < 0)
4402 mgmt_pending_remove(cmd);
4403
4404unlock:
4405 hci_dev_unlock(hdev);
4406 return err;
4407}
4408
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004409static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4410 void *data, u16 len)
4411{
4412 struct mgmt_cp_set_static_address *cp = data;
4413 int err;
4414
4415 BT_DBG("%s", hdev->name);
4416
Marcel Holtmann62af4442013-10-02 22:10:32 -07004417 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004418 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4419 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004420
4421 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004422 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4423 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004424
4425 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4426 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004427 return mgmt_cmd_status(sk, hdev->id,
4428 MGMT_OP_SET_STATIC_ADDRESS,
4429 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004430
4431 /* Two most significant bits shall be set */
4432 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004433 return mgmt_cmd_status(sk, hdev->id,
4434 MGMT_OP_SET_STATIC_ADDRESS,
4435 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004436 }
4437
4438 hci_dev_lock(hdev);
4439
4440 bacpy(&hdev->static_addr, &cp->bdaddr);
4441
Marcel Holtmann93690c22015-03-06 10:11:21 -08004442 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4443 if (err < 0)
4444 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004445
Marcel Holtmann93690c22015-03-06 10:11:21 -08004446 err = new_settings(hdev, sk);
4447
4448unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004449 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004450 return err;
4451}
4452
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004453static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4454 void *data, u16 len)
4455{
4456 struct mgmt_cp_set_scan_params *cp = data;
4457 __u16 interval, window;
4458 int err;
4459
4460 BT_DBG("%s", hdev->name);
4461
4462 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004463 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4464 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004465
4466 interval = __le16_to_cpu(cp->interval);
4467
4468 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004469 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4470 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004471
4472 window = __le16_to_cpu(cp->window);
4473
4474 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004475 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4476 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004477
Marcel Holtmann899e1072013-10-14 09:55:32 -07004478 if (window > interval)
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 Holtmann899e1072013-10-14 09:55:32 -07004481
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004482 hci_dev_lock(hdev);
4483
4484 hdev->le_scan_interval = interval;
4485 hdev->le_scan_window = window;
4486
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004487 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4488 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004489
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004490 /* If background scan is running, restart it so new parameters are
4491 * loaded.
4492 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004493 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004494 hdev->discovery.state == DISCOVERY_STOPPED) {
4495 struct hci_request req;
4496
4497 hci_req_init(&req, hdev);
4498
4499 hci_req_add_le_scan_disable(&req);
4500 hci_req_add_le_passive_scan(&req);
4501
4502 hci_req_run(&req, NULL);
4503 }
4504
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004505 hci_dev_unlock(hdev);
4506
4507 return err;
4508}
4509
Marcel Holtmann1904a852015-01-11 13:50:44 -08004510static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4511 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004512{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004513 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004514
4515 BT_DBG("status 0x%02x", status);
4516
4517 hci_dev_lock(hdev);
4518
Johan Hedberg333ae952015-03-17 13:48:47 +02004519 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004520 if (!cmd)
4521 goto unlock;
4522
4523 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004524 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4525 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004526 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004527 struct mgmt_mode *cp = cmd->param;
4528
4529 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004530 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004531 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004532 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004533
Johan Hedberg33e38b32013-03-15 17:07:05 -05004534 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4535 new_settings(hdev, cmd->sk);
4536 }
4537
4538 mgmt_pending_remove(cmd);
4539
4540unlock:
4541 hci_dev_unlock(hdev);
4542}
4543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004544static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004545 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004546{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004547 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004548 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004549 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004550 int err;
4551
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004552 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004553
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004554 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004555 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004556 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4557 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004558
Johan Hedberga7e80f22013-01-09 16:05:19 +02004559 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004560 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4561 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004562
Antti Julkuf6422ec2011-06-22 13:11:56 +03004563 hci_dev_lock(hdev);
4564
Johan Hedberg333ae952015-03-17 13:48:47 +02004565 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004566 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4567 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004568 goto unlock;
4569 }
4570
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004571 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004572 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4573 hdev);
4574 goto unlock;
4575 }
4576
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004577 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004578 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004579 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4580 hdev);
4581 new_settings(hdev, sk);
4582 goto unlock;
4583 }
4584
Johan Hedberg33e38b32013-03-15 17:07:05 -05004585 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4586 data, len);
4587 if (!cmd) {
4588 err = -ENOMEM;
4589 goto unlock;
4590 }
4591
4592 hci_req_init(&req, hdev);
4593
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004594 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004595
4596 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004597 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004598 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4599 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004600 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004601 }
4602
Johan Hedberg33e38b32013-03-15 17:07:05 -05004603unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004604 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004605
Antti Julkuf6422ec2011-06-22 13:11:56 +03004606 return err;
4607}
4608
Marcel Holtmann1904a852015-01-11 13:50:44 -08004609static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004610{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004611 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004612
4613 BT_DBG("status 0x%02x", status);
4614
4615 hci_dev_lock(hdev);
4616
Johan Hedberg333ae952015-03-17 13:48:47 +02004617 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004618 if (!cmd)
4619 goto unlock;
4620
4621 if (status) {
4622 u8 mgmt_err = mgmt_status(status);
4623
4624 /* We need to restore the flag if related HCI commands
4625 * failed.
4626 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004627 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004628
Johan Hedberga69e8372015-03-06 21:08:53 +02004629 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004630 } else {
4631 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4632 new_settings(hdev, cmd->sk);
4633 }
4634
4635 mgmt_pending_remove(cmd);
4636
4637unlock:
4638 hci_dev_unlock(hdev);
4639}
4640
4641static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4642{
4643 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004644 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004645 struct hci_request req;
4646 int err;
4647
4648 BT_DBG("request for %s", hdev->name);
4649
4650 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004651 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4652 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004653
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004654 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004655 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4656 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004657
4658 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004659 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4660 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004661
4662 hci_dev_lock(hdev);
4663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004664 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004665 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4666 goto unlock;
4667 }
4668
4669 if (!hdev_is_powered(hdev)) {
4670 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004671 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4672 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4673 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4674 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4675 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004676 }
4677
Marcel Holtmannce05d602015-03-13 02:11:03 -07004678 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004679
4680 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4681 if (err < 0)
4682 goto unlock;
4683
4684 err = new_settings(hdev, sk);
4685 goto unlock;
4686 }
4687
4688 /* Reject disabling when powered on */
4689 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004690 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4691 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004692 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004693 } else {
4694 /* When configuring a dual-mode controller to operate
4695 * with LE only and using a static address, then switching
4696 * BR/EDR back on is not allowed.
4697 *
4698 * Dual-mode controllers shall operate with the public
4699 * address as its identity address for BR/EDR and LE. So
4700 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004701 *
4702 * The same restrictions applies when secure connections
4703 * has been enabled. For BR/EDR this is a controller feature
4704 * while for LE it is a host stack feature. This means that
4705 * switching BR/EDR back on when secure connections has been
4706 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004707 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004708 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004709 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004710 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004711 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4712 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004713 goto unlock;
4714 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004715 }
4716
Johan Hedberg333ae952015-03-17 13:48:47 +02004717 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004718 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4719 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004720 goto unlock;
4721 }
4722
4723 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4724 if (!cmd) {
4725 err = -ENOMEM;
4726 goto unlock;
4727 }
4728
Johan Hedbergf2252572015-11-18 12:49:20 +02004729 /* We need to flip the bit already here so that
4730 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004731 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004732 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004733
4734 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004735
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004736 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004737 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004738
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004739 /* Since only the advertising data flags will change, there
4740 * is no need to update the scan response data.
4741 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004742 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004743
Johan Hedberg0663ca22013-10-02 13:43:14 +03004744 err = hci_req_run(&req, set_bredr_complete);
4745 if (err < 0)
4746 mgmt_pending_remove(cmd);
4747
4748unlock:
4749 hci_dev_unlock(hdev);
4750 return err;
4751}
4752
Johan Hedberga1443f52015-01-23 15:42:46 +02004753static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4754{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004755 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004756 struct mgmt_mode *cp;
4757
4758 BT_DBG("%s status %u", hdev->name, status);
4759
4760 hci_dev_lock(hdev);
4761
Johan Hedberg333ae952015-03-17 13:48:47 +02004762 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004763 if (!cmd)
4764 goto unlock;
4765
4766 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004767 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4768 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004769 goto remove;
4770 }
4771
4772 cp = cmd->param;
4773
4774 switch (cp->val) {
4775 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004776 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4777 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004778 break;
4779 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004780 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004781 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004782 break;
4783 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004784 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4785 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004786 break;
4787 }
4788
4789 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4790 new_settings(hdev, cmd->sk);
4791
4792remove:
4793 mgmt_pending_remove(cmd);
4794unlock:
4795 hci_dev_unlock(hdev);
4796}
4797
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004798static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4799 void *data, u16 len)
4800{
4801 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004802 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004803 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004804 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004805 int err;
4806
4807 BT_DBG("request for %s", hdev->name);
4808
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004809 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004810 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004811 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4812 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004813
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004814 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004815 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004816 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004817 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4818 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004819
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004820 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004821 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004822 MGMT_STATUS_INVALID_PARAMS);
4823
4824 hci_dev_lock(hdev);
4825
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004826 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004827 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004828 bool changed;
4829
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004830 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004831 changed = !hci_dev_test_and_set_flag(hdev,
4832 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004833 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004834 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004835 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004836 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004837 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004838 changed = hci_dev_test_and_clear_flag(hdev,
4839 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004840 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004841 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004842
4843 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4844 if (err < 0)
4845 goto failed;
4846
4847 if (changed)
4848 err = new_settings(hdev, sk);
4849
4850 goto failed;
4851 }
4852
Johan Hedberg333ae952015-03-17 13:48:47 +02004853 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004854 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4855 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004856 goto failed;
4857 }
4858
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004859 val = !!cp->val;
4860
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004861 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4862 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004863 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4864 goto failed;
4865 }
4866
4867 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4868 if (!cmd) {
4869 err = -ENOMEM;
4870 goto failed;
4871 }
4872
Johan Hedberga1443f52015-01-23 15:42:46 +02004873 hci_req_init(&req, hdev);
4874 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4875 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004876 if (err < 0) {
4877 mgmt_pending_remove(cmd);
4878 goto failed;
4879 }
4880
4881failed:
4882 hci_dev_unlock(hdev);
4883 return err;
4884}
4885
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004886static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4887 void *data, u16 len)
4888{
4889 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004890 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004891 int err;
4892
4893 BT_DBG("request for %s", hdev->name);
4894
Johan Hedbergb97109792014-06-24 14:00:28 +03004895 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004896 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4897 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004898
4899 hci_dev_lock(hdev);
4900
4901 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004902 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004903 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004904 changed = hci_dev_test_and_clear_flag(hdev,
4905 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004906
Johan Hedbergb97109792014-06-24 14:00:28 +03004907 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004908 use_changed = !hci_dev_test_and_set_flag(hdev,
4909 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004910 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004911 use_changed = hci_dev_test_and_clear_flag(hdev,
4912 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004913
4914 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004915 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004916 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4917 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4918 sizeof(mode), &mode);
4919 }
4920
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004921 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4922 if (err < 0)
4923 goto unlock;
4924
4925 if (changed)
4926 err = new_settings(hdev, sk);
4927
4928unlock:
4929 hci_dev_unlock(hdev);
4930 return err;
4931}
4932
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004933static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4934 u16 len)
4935{
4936 struct mgmt_cp_set_privacy *cp = cp_data;
4937 bool changed;
4938 int err;
4939
4940 BT_DBG("request for %s", hdev->name);
4941
4942 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004943 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4944 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004945
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004946 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004947 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4948 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004949
4950 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004951 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4952 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004953
4954 hci_dev_lock(hdev);
4955
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004956 /* If user space supports this command it is also expected to
4957 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4958 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004959 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004960
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004961 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004962 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004963 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004964 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004965 if (cp->privacy == 0x02)
4966 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4967 else
4968 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004969 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004970 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004971 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004972 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004973 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004974 }
4975
4976 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4977 if (err < 0)
4978 goto unlock;
4979
4980 if (changed)
4981 err = new_settings(hdev, sk);
4982
4983unlock:
4984 hci_dev_unlock(hdev);
4985 return err;
4986}
4987
Johan Hedberg41edf162014-02-18 10:19:35 +02004988static bool irk_is_valid(struct mgmt_irk_info *irk)
4989{
4990 switch (irk->addr.type) {
4991 case BDADDR_LE_PUBLIC:
4992 return true;
4993
4994 case BDADDR_LE_RANDOM:
4995 /* Two most significant bits shall be set */
4996 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4997 return false;
4998 return true;
4999 }
5000
5001 return false;
5002}
5003
5004static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5005 u16 len)
5006{
5007 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005008 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5009 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005010 u16 irk_count, expected_len;
5011 int i, err;
5012
5013 BT_DBG("request for %s", hdev->name);
5014
5015 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005016 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5017 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005018
5019 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005020 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005021 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5022 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005023 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5024 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005025 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005026
5027 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5028 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005029 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5030 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005031 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5032 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005033 }
5034
5035 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5036
5037 for (i = 0; i < irk_count; i++) {
5038 struct mgmt_irk_info *key = &cp->irks[i];
5039
5040 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005041 return mgmt_cmd_status(sk, hdev->id,
5042 MGMT_OP_LOAD_IRKS,
5043 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005044 }
5045
5046 hci_dev_lock(hdev);
5047
5048 hci_smp_irks_clear(hdev);
5049
5050 for (i = 0; i < irk_count; i++) {
5051 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005052
Johan Hedberg85813a72015-10-21 18:02:59 +03005053 hci_add_irk(hdev, &irk->addr.bdaddr,
5054 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005055 BDADDR_ANY);
5056 }
5057
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005058 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005059
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005060 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005061
5062 hci_dev_unlock(hdev);
5063
5064 return err;
5065}
5066
Johan Hedberg3f706b72013-01-20 14:27:16 +02005067static bool ltk_is_valid(struct mgmt_ltk_info *key)
5068{
5069 if (key->master != 0x00 && key->master != 0x01)
5070 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005071
5072 switch (key->addr.type) {
5073 case BDADDR_LE_PUBLIC:
5074 return true;
5075
5076 case BDADDR_LE_RANDOM:
5077 /* Two most significant bits shall be set */
5078 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5079 return false;
5080 return true;
5081 }
5082
5083 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005084}
5085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005086static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005087 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005088{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005089 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005090 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5091 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005092 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005093 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005094
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005095 BT_DBG("request for %s", hdev->name);
5096
5097 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005098 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5099 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005100
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005101 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005102 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005103 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5104 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005105 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5106 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005107 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005108
5109 expected_len = sizeof(*cp) + key_count *
5110 sizeof(struct mgmt_ltk_info);
5111 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005112 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5113 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005114 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5115 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005116 }
5117
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005118 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005119
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005120 for (i = 0; i < key_count; i++) {
5121 struct mgmt_ltk_info *key = &cp->keys[i];
5122
Johan Hedberg3f706b72013-01-20 14:27:16 +02005123 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005124 return mgmt_cmd_status(sk, hdev->id,
5125 MGMT_OP_LOAD_LONG_TERM_KEYS,
5126 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005127 }
5128
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005129 hci_dev_lock(hdev);
5130
5131 hci_smp_ltks_clear(hdev);
5132
5133 for (i = 0; i < key_count; i++) {
5134 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005135 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005136
Johan Hedberg61b43352014-05-29 19:36:53 +03005137 switch (key->type) {
5138 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005139 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005140 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005141 break;
5142 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005143 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005144 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005145 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005146 case MGMT_LTK_P256_UNAUTH:
5147 authenticated = 0x00;
5148 type = SMP_LTK_P256;
5149 break;
5150 case MGMT_LTK_P256_AUTH:
5151 authenticated = 0x01;
5152 type = SMP_LTK_P256;
5153 break;
5154 case MGMT_LTK_P256_DEBUG:
5155 authenticated = 0x00;
5156 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005157 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005158 default:
5159 continue;
5160 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005161
Johan Hedberg85813a72015-10-21 18:02:59 +03005162 hci_add_ltk(hdev, &key->addr.bdaddr,
5163 le_addr_type(key->addr.type), type, authenticated,
5164 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005165 }
5166
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005167 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005168 NULL, 0);
5169
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005170 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005171
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005172 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005173}
5174
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005175static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005176{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005177 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005178 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005179 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005180
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005181 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005182
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005183 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005184 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005185 rp.tx_power = conn->tx_power;
5186 rp.max_tx_power = conn->max_tx_power;
5187 } else {
5188 rp.rssi = HCI_RSSI_INVALID;
5189 rp.tx_power = HCI_TX_POWER_INVALID;
5190 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005191 }
5192
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005193 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5194 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005195
5196 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005197 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005198
5199 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005200}
5201
Marcel Holtmann1904a852015-01-11 13:50:44 -08005202static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5203 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005204{
5205 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005206 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005207 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005208 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005209 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005210
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005211 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005212
5213 hci_dev_lock(hdev);
5214
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005215 /* Commands sent in request are either Read RSSI or Read Transmit Power
5216 * Level so we check which one was last sent to retrieve connection
5217 * handle. Both commands have handle as first parameter so it's safe to
5218 * cast data on the same command struct.
5219 *
5220 * First command sent is always Read RSSI and we fail only if it fails.
5221 * In other case we simply override error to indicate success as we
5222 * already remembered if TX power value is actually valid.
5223 */
5224 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5225 if (!cp) {
5226 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005227 status = MGMT_STATUS_SUCCESS;
5228 } else {
5229 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005230 }
5231
5232 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005233 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005234 goto unlock;
5235 }
5236
5237 handle = __le16_to_cpu(cp->handle);
5238 conn = hci_conn_hash_lookup_handle(hdev, handle);
5239 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005240 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5241 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005242 goto unlock;
5243 }
5244
Johan Hedberg333ae952015-03-17 13:48:47 +02005245 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005246 if (!cmd)
5247 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005248
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005249 cmd->cmd_complete(cmd, status);
5250 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005251
5252unlock:
5253 hci_dev_unlock(hdev);
5254}
5255
5256static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5257 u16 len)
5258{
5259 struct mgmt_cp_get_conn_info *cp = data;
5260 struct mgmt_rp_get_conn_info rp;
5261 struct hci_conn *conn;
5262 unsigned long conn_info_age;
5263 int err = 0;
5264
5265 BT_DBG("%s", hdev->name);
5266
5267 memset(&rp, 0, sizeof(rp));
5268 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5269 rp.addr.type = cp->addr.type;
5270
5271 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005272 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5273 MGMT_STATUS_INVALID_PARAMS,
5274 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005275
5276 hci_dev_lock(hdev);
5277
5278 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005279 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5280 MGMT_STATUS_NOT_POWERED, &rp,
5281 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005282 goto unlock;
5283 }
5284
5285 if (cp->addr.type == BDADDR_BREDR)
5286 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5287 &cp->addr.bdaddr);
5288 else
5289 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5290
5291 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005292 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5293 MGMT_STATUS_NOT_CONNECTED, &rp,
5294 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005295 goto unlock;
5296 }
5297
Johan Hedberg333ae952015-03-17 13:48:47 +02005298 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005299 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5300 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005301 goto unlock;
5302 }
5303
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005304 /* To avoid client trying to guess when to poll again for information we
5305 * calculate conn info age as random value between min/max set in hdev.
5306 */
5307 conn_info_age = hdev->conn_info_min_age +
5308 prandom_u32_max(hdev->conn_info_max_age -
5309 hdev->conn_info_min_age);
5310
5311 /* Query controller to refresh cached values if they are too old or were
5312 * never read.
5313 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005314 if (time_after(jiffies, conn->conn_info_timestamp +
5315 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005316 !conn->conn_info_timestamp) {
5317 struct hci_request req;
5318 struct hci_cp_read_tx_power req_txp_cp;
5319 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005320 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005321
5322 hci_req_init(&req, hdev);
5323 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5324 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5325 &req_rssi_cp);
5326
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005327 /* For LE links TX power does not change thus we don't need to
5328 * query for it once value is known.
5329 */
5330 if (!bdaddr_type_is_le(cp->addr.type) ||
5331 conn->tx_power == HCI_TX_POWER_INVALID) {
5332 req_txp_cp.handle = cpu_to_le16(conn->handle);
5333 req_txp_cp.type = 0x00;
5334 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5335 sizeof(req_txp_cp), &req_txp_cp);
5336 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005337
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005338 /* Max TX power needs to be read only once per connection */
5339 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5340 req_txp_cp.handle = cpu_to_le16(conn->handle);
5341 req_txp_cp.type = 0x01;
5342 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5343 sizeof(req_txp_cp), &req_txp_cp);
5344 }
5345
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005346 err = hci_req_run(&req, conn_info_refresh_complete);
5347 if (err < 0)
5348 goto unlock;
5349
5350 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5351 data, len);
5352 if (!cmd) {
5353 err = -ENOMEM;
5354 goto unlock;
5355 }
5356
5357 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005358 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005359 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005360
5361 conn->conn_info_timestamp = jiffies;
5362 } else {
5363 /* Cache is valid, just reply with values cached in hci_conn */
5364 rp.rssi = conn->rssi;
5365 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005366 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005367
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005368 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5369 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005370 }
5371
5372unlock:
5373 hci_dev_unlock(hdev);
5374 return err;
5375}
5376
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005377static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005378{
5379 struct hci_conn *conn = cmd->user_data;
5380 struct mgmt_rp_get_clock_info rp;
5381 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005382 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005383
5384 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005385 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005386
5387 if (status)
5388 goto complete;
5389
5390 hdev = hci_dev_get(cmd->index);
5391 if (hdev) {
5392 rp.local_clock = cpu_to_le32(hdev->clock);
5393 hci_dev_put(hdev);
5394 }
5395
5396 if (conn) {
5397 rp.piconet_clock = cpu_to_le32(conn->clock);
5398 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5399 }
5400
5401complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005402 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5403 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005404
5405 if (conn) {
5406 hci_conn_drop(conn);
5407 hci_conn_put(conn);
5408 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005409
5410 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005411}
5412
Marcel Holtmann1904a852015-01-11 13:50:44 -08005413static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005414{
Johan Hedberg95868422014-06-28 17:54:07 +03005415 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005416 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005417 struct hci_conn *conn;
5418
5419 BT_DBG("%s status %u", hdev->name, status);
5420
5421 hci_dev_lock(hdev);
5422
5423 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5424 if (!hci_cp)
5425 goto unlock;
5426
5427 if (hci_cp->which) {
5428 u16 handle = __le16_to_cpu(hci_cp->handle);
5429 conn = hci_conn_hash_lookup_handle(hdev, handle);
5430 } else {
5431 conn = NULL;
5432 }
5433
Johan Hedberg333ae952015-03-17 13:48:47 +02005434 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005435 if (!cmd)
5436 goto unlock;
5437
Johan Hedberg69487372014-12-05 13:36:07 +02005438 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005439 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005440
5441unlock:
5442 hci_dev_unlock(hdev);
5443}
5444
5445static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5446 u16 len)
5447{
5448 struct mgmt_cp_get_clock_info *cp = data;
5449 struct mgmt_rp_get_clock_info rp;
5450 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005451 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005452 struct hci_request req;
5453 struct hci_conn *conn;
5454 int err;
5455
5456 BT_DBG("%s", hdev->name);
5457
5458 memset(&rp, 0, sizeof(rp));
5459 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5460 rp.addr.type = cp->addr.type;
5461
5462 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005463 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5464 MGMT_STATUS_INVALID_PARAMS,
5465 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005466
5467 hci_dev_lock(hdev);
5468
5469 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005470 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5471 MGMT_STATUS_NOT_POWERED, &rp,
5472 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005473 goto unlock;
5474 }
5475
5476 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5477 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5478 &cp->addr.bdaddr);
5479 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005480 err = mgmt_cmd_complete(sk, hdev->id,
5481 MGMT_OP_GET_CLOCK_INFO,
5482 MGMT_STATUS_NOT_CONNECTED,
5483 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005484 goto unlock;
5485 }
5486 } else {
5487 conn = NULL;
5488 }
5489
5490 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5491 if (!cmd) {
5492 err = -ENOMEM;
5493 goto unlock;
5494 }
5495
Johan Hedberg69487372014-12-05 13:36:07 +02005496 cmd->cmd_complete = clock_info_cmd_complete;
5497
Johan Hedberg95868422014-06-28 17:54:07 +03005498 hci_req_init(&req, hdev);
5499
5500 memset(&hci_cp, 0, sizeof(hci_cp));
5501 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5502
5503 if (conn) {
5504 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005505 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005506
5507 hci_cp.handle = cpu_to_le16(conn->handle);
5508 hci_cp.which = 0x01; /* Piconet clock */
5509 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5510 }
5511
5512 err = hci_req_run(&req, get_clock_info_complete);
5513 if (err < 0)
5514 mgmt_pending_remove(cmd);
5515
5516unlock:
5517 hci_dev_unlock(hdev);
5518 return err;
5519}
5520
Johan Hedberg5a154e62014-12-19 22:26:02 +02005521static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5522{
5523 struct hci_conn *conn;
5524
5525 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5526 if (!conn)
5527 return false;
5528
5529 if (conn->dst_type != type)
5530 return false;
5531
5532 if (conn->state != BT_CONNECTED)
5533 return false;
5534
5535 return true;
5536}
5537
5538/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005539static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005540 u8 addr_type, u8 auto_connect)
5541{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005542 struct hci_conn_params *params;
5543
5544 params = hci_conn_params_add(hdev, addr, addr_type);
5545 if (!params)
5546 return -EIO;
5547
5548 if (params->auto_connect == auto_connect)
5549 return 0;
5550
5551 list_del_init(&params->action);
5552
5553 switch (auto_connect) {
5554 case HCI_AUTO_CONN_DISABLED:
5555 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005556 /* If auto connect is being disabled when we're trying to
5557 * connect to device, keep connecting.
5558 */
5559 if (params->explicit_connect)
5560 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005561 break;
5562 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005563 if (params->explicit_connect)
5564 list_add(&params->action, &hdev->pend_le_conns);
5565 else
5566 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005567 break;
5568 case HCI_AUTO_CONN_DIRECT:
5569 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005570 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005571 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005572 break;
5573 }
5574
5575 params->auto_connect = auto_connect;
5576
5577 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5578 auto_connect);
5579
5580 return 0;
5581}
5582
Marcel Holtmann8afef092014-06-29 22:28:34 +02005583static void device_added(struct sock *sk, struct hci_dev *hdev,
5584 bdaddr_t *bdaddr, u8 type, u8 action)
5585{
5586 struct mgmt_ev_device_added ev;
5587
5588 bacpy(&ev.addr.bdaddr, bdaddr);
5589 ev.addr.type = type;
5590 ev.action = action;
5591
5592 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5593}
5594
Marcel Holtmann2faade52014-06-29 19:44:03 +02005595static int add_device(struct sock *sk, struct hci_dev *hdev,
5596 void *data, u16 len)
5597{
5598 struct mgmt_cp_add_device *cp = data;
5599 u8 auto_conn, addr_type;
5600 int err;
5601
5602 BT_DBG("%s", hdev->name);
5603
Johan Hedberg66593582014-07-09 12:59:14 +03005604 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005605 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005606 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5607 MGMT_STATUS_INVALID_PARAMS,
5608 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005609
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005610 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005611 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5612 MGMT_STATUS_INVALID_PARAMS,
5613 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005614
5615 hci_dev_lock(hdev);
5616
Johan Hedberg66593582014-07-09 12:59:14 +03005617 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005618 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005619 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005620 err = mgmt_cmd_complete(sk, hdev->id,
5621 MGMT_OP_ADD_DEVICE,
5622 MGMT_STATUS_INVALID_PARAMS,
5623 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005624 goto unlock;
5625 }
5626
5627 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5628 cp->addr.type);
5629 if (err)
5630 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005631
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005632 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005633
Johan Hedberg66593582014-07-09 12:59:14 +03005634 goto added;
5635 }
5636
Johan Hedberg85813a72015-10-21 18:02:59 +03005637 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005638
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005639 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005640 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005641 else if (cp->action == 0x01)
5642 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005643 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005644 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005645
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005646 /* Kernel internally uses conn_params with resolvable private
5647 * address, but Add Device allows only identity addresses.
5648 * Make sure it is enforced before calling
5649 * hci_conn_params_lookup.
5650 */
5651 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005652 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5653 MGMT_STATUS_INVALID_PARAMS,
5654 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005655 goto unlock;
5656 }
5657
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005658 /* If the connection parameters don't exist for this device,
5659 * they will be created and configured with defaults.
5660 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005661 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005662 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005663 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5664 MGMT_STATUS_FAILED, &cp->addr,
5665 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005666 goto unlock;
5667 }
5668
Johan Hedberg51d7a942015-11-11 08:11:18 +02005669 hci_update_background_scan(hdev);
5670
Johan Hedberg66593582014-07-09 12:59:14 +03005671added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005672 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5673
Johan Hedberg51d7a942015-11-11 08:11:18 +02005674 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5675 MGMT_STATUS_SUCCESS, &cp->addr,
5676 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005677
5678unlock:
5679 hci_dev_unlock(hdev);
5680 return err;
5681}
5682
Marcel Holtmann8afef092014-06-29 22:28:34 +02005683static void device_removed(struct sock *sk, struct hci_dev *hdev,
5684 bdaddr_t *bdaddr, u8 type)
5685{
5686 struct mgmt_ev_device_removed ev;
5687
5688 bacpy(&ev.addr.bdaddr, bdaddr);
5689 ev.addr.type = type;
5690
5691 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5692}
5693
Marcel Holtmann2faade52014-06-29 19:44:03 +02005694static int remove_device(struct sock *sk, struct hci_dev *hdev,
5695 void *data, u16 len)
5696{
5697 struct mgmt_cp_remove_device *cp = data;
5698 int err;
5699
5700 BT_DBG("%s", hdev->name);
5701
5702 hci_dev_lock(hdev);
5703
5704 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005705 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005706 u8 addr_type;
5707
Johan Hedberg66593582014-07-09 12:59:14 +03005708 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005709 err = mgmt_cmd_complete(sk, hdev->id,
5710 MGMT_OP_REMOVE_DEVICE,
5711 MGMT_STATUS_INVALID_PARAMS,
5712 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005713 goto unlock;
5714 }
5715
Johan Hedberg66593582014-07-09 12:59:14 +03005716 if (cp->addr.type == BDADDR_BREDR) {
5717 err = hci_bdaddr_list_del(&hdev->whitelist,
5718 &cp->addr.bdaddr,
5719 cp->addr.type);
5720 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005721 err = mgmt_cmd_complete(sk, hdev->id,
5722 MGMT_OP_REMOVE_DEVICE,
5723 MGMT_STATUS_INVALID_PARAMS,
5724 &cp->addr,
5725 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005726 goto unlock;
5727 }
5728
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005729 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005730
Johan Hedberg66593582014-07-09 12:59:14 +03005731 device_removed(sk, hdev, &cp->addr.bdaddr,
5732 cp->addr.type);
5733 goto complete;
5734 }
5735
Johan Hedberg85813a72015-10-21 18:02:59 +03005736 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005737
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005738 /* Kernel internally uses conn_params with resolvable private
5739 * address, but Remove Device allows only identity addresses.
5740 * Make sure it is enforced before calling
5741 * hci_conn_params_lookup.
5742 */
5743 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005744 err = mgmt_cmd_complete(sk, hdev->id,
5745 MGMT_OP_REMOVE_DEVICE,
5746 MGMT_STATUS_INVALID_PARAMS,
5747 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005748 goto unlock;
5749 }
5750
Johan Hedbergc71593d2014-07-02 17:37:28 +03005751 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5752 addr_type);
5753 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005754 err = mgmt_cmd_complete(sk, hdev->id,
5755 MGMT_OP_REMOVE_DEVICE,
5756 MGMT_STATUS_INVALID_PARAMS,
5757 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005758 goto unlock;
5759 }
5760
Johan Hedberg679d2b62015-10-16 10:07:52 +03005761 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5762 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005763 err = mgmt_cmd_complete(sk, hdev->id,
5764 MGMT_OP_REMOVE_DEVICE,
5765 MGMT_STATUS_INVALID_PARAMS,
5766 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005767 goto unlock;
5768 }
5769
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005770 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005771 list_del(&params->list);
5772 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005773 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005774
5775 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005776 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005777 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005778 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005779
Marcel Holtmann2faade52014-06-29 19:44:03 +02005780 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005781 err = mgmt_cmd_complete(sk, hdev->id,
5782 MGMT_OP_REMOVE_DEVICE,
5783 MGMT_STATUS_INVALID_PARAMS,
5784 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005785 goto unlock;
5786 }
5787
Johan Hedberg66593582014-07-09 12:59:14 +03005788 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5789 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5790 list_del(&b->list);
5791 kfree(b);
5792 }
5793
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005794 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005795
Johan Hedberg19de0822014-07-06 13:06:51 +03005796 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5797 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5798 continue;
5799 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005800 if (p->explicit_connect) {
5801 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5802 continue;
5803 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005804 list_del(&p->action);
5805 list_del(&p->list);
5806 kfree(p);
5807 }
5808
5809 BT_DBG("All LE connection parameters were removed");
5810
Johan Hedberg51d7a942015-11-11 08:11:18 +02005811 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005812 }
5813
Johan Hedberg66593582014-07-09 12:59:14 +03005814complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005815 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5816 MGMT_STATUS_SUCCESS, &cp->addr,
5817 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005818unlock:
5819 hci_dev_unlock(hdev);
5820 return err;
5821}
5822
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005823static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5824 u16 len)
5825{
5826 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005827 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5828 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005829 u16 param_count, expected_len;
5830 int i;
5831
5832 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005833 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5834 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005835
5836 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005837 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005838 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
5839 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005840 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5841 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005842 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005843
5844 expected_len = sizeof(*cp) + param_count *
5845 sizeof(struct mgmt_conn_param);
5846 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005847 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
5848 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005849 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5850 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005851 }
5852
5853 BT_DBG("%s param_count %u", hdev->name, param_count);
5854
5855 hci_dev_lock(hdev);
5856
5857 hci_conn_params_clear_disabled(hdev);
5858
5859 for (i = 0; i < param_count; i++) {
5860 struct mgmt_conn_param *param = &cp->params[i];
5861 struct hci_conn_params *hci_param;
5862 u16 min, max, latency, timeout;
5863 u8 addr_type;
5864
5865 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5866 param->addr.type);
5867
5868 if (param->addr.type == BDADDR_LE_PUBLIC) {
5869 addr_type = ADDR_LE_DEV_PUBLIC;
5870 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5871 addr_type = ADDR_LE_DEV_RANDOM;
5872 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005873 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005874 continue;
5875 }
5876
5877 min = le16_to_cpu(param->min_interval);
5878 max = le16_to_cpu(param->max_interval);
5879 latency = le16_to_cpu(param->latency);
5880 timeout = le16_to_cpu(param->timeout);
5881
5882 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5883 min, max, latency, timeout);
5884
5885 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005886 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005887 continue;
5888 }
5889
5890 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5891 addr_type);
5892 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005893 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005894 continue;
5895 }
5896
5897 hci_param->conn_min_interval = min;
5898 hci_param->conn_max_interval = max;
5899 hci_param->conn_latency = latency;
5900 hci_param->supervision_timeout = timeout;
5901 }
5902
5903 hci_dev_unlock(hdev);
5904
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005905 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5906 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005907}
5908
Marcel Holtmanndbece372014-07-04 18:11:55 +02005909static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5910 void *data, u16 len)
5911{
5912 struct mgmt_cp_set_external_config *cp = data;
5913 bool changed;
5914 int err;
5915
5916 BT_DBG("%s", hdev->name);
5917
5918 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005919 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5920 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005921
5922 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005923 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5924 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005925
5926 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005927 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5928 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005929
5930 hci_dev_lock(hdev);
5931
5932 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005933 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005934 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005935 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005936
5937 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5938 if (err < 0)
5939 goto unlock;
5940
5941 if (!changed)
5942 goto unlock;
5943
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005944 err = new_options(hdev, sk);
5945
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005946 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005947 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005948
Marcel Holtmann516018a2015-03-13 02:11:04 -07005949 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005950 hci_dev_set_flag(hdev, HCI_CONFIG);
5951 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005952
5953 queue_work(hdev->req_workqueue, &hdev->power_on);
5954 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005955 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005956 mgmt_index_added(hdev);
5957 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005958 }
5959
5960unlock:
5961 hci_dev_unlock(hdev);
5962 return err;
5963}
5964
Marcel Holtmann9713c172014-07-06 12:11:15 +02005965static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5966 void *data, u16 len)
5967{
5968 struct mgmt_cp_set_public_address *cp = data;
5969 bool changed;
5970 int err;
5971
5972 BT_DBG("%s", hdev->name);
5973
5974 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005975 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5976 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005977
5978 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005979 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5980 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005981
5982 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005983 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5984 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005985
5986 hci_dev_lock(hdev);
5987
5988 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5989 bacpy(&hdev->public_addr, &cp->bdaddr);
5990
5991 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5992 if (err < 0)
5993 goto unlock;
5994
5995 if (!changed)
5996 goto unlock;
5997
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005998 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005999 err = new_options(hdev, sk);
6000
6001 if (is_configured(hdev)) {
6002 mgmt_index_removed(hdev);
6003
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006004 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006005
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006006 hci_dev_set_flag(hdev, HCI_CONFIG);
6007 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006008
6009 queue_work(hdev->req_workqueue, &hdev->power_on);
6010 }
6011
6012unlock:
6013 hci_dev_unlock(hdev);
6014 return err;
6015}
6016
Johan Hedberg40f66c02015-04-07 21:52:22 +03006017static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6018 u16 opcode, struct sk_buff *skb)
6019{
6020 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6021 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6022 u8 *h192, *r192, *h256, *r256;
6023 struct mgmt_pending_cmd *cmd;
6024 u16 eir_len;
6025 int err;
6026
6027 BT_DBG("%s status %u", hdev->name, status);
6028
6029 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6030 if (!cmd)
6031 return;
6032
6033 mgmt_cp = cmd->param;
6034
6035 if (status) {
6036 status = mgmt_status(status);
6037 eir_len = 0;
6038
6039 h192 = NULL;
6040 r192 = NULL;
6041 h256 = NULL;
6042 r256 = NULL;
6043 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6044 struct hci_rp_read_local_oob_data *rp;
6045
6046 if (skb->len != sizeof(*rp)) {
6047 status = MGMT_STATUS_FAILED;
6048 eir_len = 0;
6049 } else {
6050 status = MGMT_STATUS_SUCCESS;
6051 rp = (void *)skb->data;
6052
6053 eir_len = 5 + 18 + 18;
6054 h192 = rp->hash;
6055 r192 = rp->rand;
6056 h256 = NULL;
6057 r256 = NULL;
6058 }
6059 } else {
6060 struct hci_rp_read_local_oob_ext_data *rp;
6061
6062 if (skb->len != sizeof(*rp)) {
6063 status = MGMT_STATUS_FAILED;
6064 eir_len = 0;
6065 } else {
6066 status = MGMT_STATUS_SUCCESS;
6067 rp = (void *)skb->data;
6068
6069 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6070 eir_len = 5 + 18 + 18;
6071 h192 = NULL;
6072 r192 = NULL;
6073 } else {
6074 eir_len = 5 + 18 + 18 + 18 + 18;
6075 h192 = rp->hash192;
6076 r192 = rp->rand192;
6077 }
6078
6079 h256 = rp->hash256;
6080 r256 = rp->rand256;
6081 }
6082 }
6083
6084 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6085 if (!mgmt_rp)
6086 goto done;
6087
6088 if (status)
6089 goto send_rsp;
6090
6091 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6092 hdev->dev_class, 3);
6093
6094 if (h192 && r192) {
6095 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6096 EIR_SSP_HASH_C192, h192, 16);
6097 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6098 EIR_SSP_RAND_R192, r192, 16);
6099 }
6100
6101 if (h256 && r256) {
6102 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6103 EIR_SSP_HASH_C256, h256, 16);
6104 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6105 EIR_SSP_RAND_R256, r256, 16);
6106 }
6107
6108send_rsp:
6109 mgmt_rp->type = mgmt_cp->type;
6110 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6111
6112 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6113 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6114 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6115 if (err < 0 || status)
6116 goto done;
6117
6118 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6119
6120 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6121 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6122 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6123done:
6124 kfree(mgmt_rp);
6125 mgmt_pending_remove(cmd);
6126}
6127
6128static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6129 struct mgmt_cp_read_local_oob_ext_data *cp)
6130{
6131 struct mgmt_pending_cmd *cmd;
6132 struct hci_request req;
6133 int err;
6134
6135 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6136 cp, sizeof(*cp));
6137 if (!cmd)
6138 return -ENOMEM;
6139
6140 hci_req_init(&req, hdev);
6141
6142 if (bredr_sc_enabled(hdev))
6143 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6144 else
6145 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6146
6147 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6148 if (err < 0) {
6149 mgmt_pending_remove(cmd);
6150 return err;
6151 }
6152
6153 return 0;
6154}
6155
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006156static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6157 void *data, u16 data_len)
6158{
6159 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6160 struct mgmt_rp_read_local_oob_ext_data *rp;
6161 size_t rp_len;
6162 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006163 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006164 int err;
6165
6166 BT_DBG("%s", hdev->name);
6167
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006168 if (hdev_is_powered(hdev)) {
6169 switch (cp->type) {
6170 case BIT(BDADDR_BREDR):
6171 status = mgmt_bredr_support(hdev);
6172 if (status)
6173 eir_len = 0;
6174 else
6175 eir_len = 5;
6176 break;
6177 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6178 status = mgmt_le_support(hdev);
6179 if (status)
6180 eir_len = 0;
6181 else
6182 eir_len = 9 + 3 + 18 + 18 + 3;
6183 break;
6184 default:
6185 status = MGMT_STATUS_INVALID_PARAMS;
6186 eir_len = 0;
6187 break;
6188 }
6189 } else {
6190 status = MGMT_STATUS_NOT_POWERED;
6191 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006192 }
6193
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006194 rp_len = sizeof(*rp) + eir_len;
6195 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006196 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006197 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006198
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006199 if (status)
6200 goto complete;
6201
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006202 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006203
6204 eir_len = 0;
6205 switch (cp->type) {
6206 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006207 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6208 err = read_local_ssp_oob_req(hdev, sk, cp);
6209 hci_dev_unlock(hdev);
6210 if (!err)
6211 goto done;
6212
6213 status = MGMT_STATUS_FAILED;
6214 goto complete;
6215 } else {
6216 eir_len = eir_append_data(rp->eir, eir_len,
6217 EIR_CLASS_OF_DEV,
6218 hdev->dev_class, 3);
6219 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006220 break;
6221 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006222 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6223 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006224 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006225 status = MGMT_STATUS_FAILED;
6226 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006227 }
6228
Marcel Holtmanne2135682015-04-02 12:00:58 -07006229 /* This should return the active RPA, but since the RPA
6230 * is only programmed on demand, it is really hard to fill
6231 * this in at the moment. For now disallow retrieving
6232 * local out-of-band data when privacy is in use.
6233 *
6234 * Returning the identity address will not help here since
6235 * pairing happens before the identity resolving key is
6236 * known and thus the connection establishment happens
6237 * based on the RPA and not the identity address.
6238 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006239 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006240 hci_dev_unlock(hdev);
6241 status = MGMT_STATUS_REJECTED;
6242 goto complete;
6243 }
6244
6245 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6246 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6247 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6248 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006249 memcpy(addr, &hdev->static_addr, 6);
6250 addr[6] = 0x01;
6251 } else {
6252 memcpy(addr, &hdev->bdaddr, 6);
6253 addr[6] = 0x00;
6254 }
6255
6256 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6257 addr, sizeof(addr));
6258
6259 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6260 role = 0x02;
6261 else
6262 role = 0x01;
6263
6264 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6265 &role, sizeof(role));
6266
Marcel Holtmann5082a592015-03-16 12:39:00 -07006267 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6268 eir_len = eir_append_data(rp->eir, eir_len,
6269 EIR_LE_SC_CONFIRM,
6270 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006271
Marcel Holtmann5082a592015-03-16 12:39:00 -07006272 eir_len = eir_append_data(rp->eir, eir_len,
6273 EIR_LE_SC_RANDOM,
6274 rand, sizeof(rand));
6275 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006276
Johan Hedbergf2252572015-11-18 12:49:20 +02006277 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006278
6279 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6280 flags |= LE_AD_NO_BREDR;
6281
6282 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6283 &flags, sizeof(flags));
6284 break;
6285 }
6286
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006287 hci_dev_unlock(hdev);
6288
Marcel Holtmann72000df2015-03-16 16:11:21 -07006289 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6290
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006291 status = MGMT_STATUS_SUCCESS;
6292
6293complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006294 rp->type = cp->type;
6295 rp->eir_len = cpu_to_le16(eir_len);
6296
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006297 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006298 status, rp, sizeof(*rp) + eir_len);
6299 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006300 goto done;
6301
6302 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6303 rp, sizeof(*rp) + eir_len,
6304 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006305
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006306done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006307 kfree(rp);
6308
6309 return err;
6310}
6311
Arman Uguray089fa8c2015-03-25 18:53:45 -07006312static u32 get_supported_adv_flags(struct hci_dev *hdev)
6313{
6314 u32 flags = 0;
6315
6316 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6317 flags |= MGMT_ADV_FLAG_DISCOV;
6318 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6319 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006320 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006321 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006322
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306323 /* In extended adv TX_POWER returned from Set Adv Param
6324 * will be always valid.
6325 */
6326 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6327 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006328 flags |= MGMT_ADV_FLAG_TX_POWER;
6329
6330 return flags;
6331}
6332
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006333static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6334 void *data, u16 data_len)
6335{
6336 struct mgmt_rp_read_adv_features *rp;
6337 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006338 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006339 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006340 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006341 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006342
6343 BT_DBG("%s", hdev->name);
6344
Arman Uguray089fa8c2015-03-25 18:53:45 -07006345 if (!lmp_le_capable(hdev))
6346 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6347 MGMT_STATUS_REJECTED);
6348
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006349 hci_dev_lock(hdev);
6350
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006351 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006352 rp = kmalloc(rp_len, GFP_ATOMIC);
6353 if (!rp) {
6354 hci_dev_unlock(hdev);
6355 return -ENOMEM;
6356 }
6357
Arman Uguray089fa8c2015-03-25 18:53:45 -07006358 supported_flags = get_supported_adv_flags(hdev);
6359
6360 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006361 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6362 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006363 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006364 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006365
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006366 instance = rp->instance;
6367 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6368 *instance = adv_instance->instance;
6369 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006370 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006371
6372 hci_dev_unlock(hdev);
6373
6374 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6375 MGMT_STATUS_SUCCESS, rp, rp_len);
6376
6377 kfree(rp);
6378
6379 return err;
6380}
6381
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006382static u8 calculate_name_len(struct hci_dev *hdev)
6383{
6384 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6385
6386 return append_local_name(hdev, buf, 0);
6387}
6388
6389static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6390 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006391{
Arman Uguray4117ed72015-03-23 15:57:14 -07006392 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006393
Marcel Holtmann31a32482015-11-19 16:16:42 +01006394 if (is_adv_data) {
6395 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6396 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006397 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006398 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006399
Szymon Janc2bb368702016-09-18 12:50:05 +02006400 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006401 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006402 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006403 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006404 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006405
Szymon Janc2bb368702016-09-18 12:50:05 +02006406 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006407 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006408 }
6409
Szymon Janc2bb368702016-09-18 12:50:05 +02006410 return max_len;
6411}
6412
6413static bool flags_managed(u32 adv_flags)
6414{
6415 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6416 MGMT_ADV_FLAG_LIMITED_DISCOV |
6417 MGMT_ADV_FLAG_MANAGED_FLAGS);
6418}
6419
6420static bool tx_power_managed(u32 adv_flags)
6421{
6422 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6423}
6424
6425static bool name_managed(u32 adv_flags)
6426{
6427 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6428}
6429
6430static bool appearance_managed(u32 adv_flags)
6431{
6432 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6433}
6434
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006435static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6436 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006437{
6438 int i, cur_len;
6439 u8 max_len;
6440
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006441 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02006442
Arman Uguray4117ed72015-03-23 15:57:14 -07006443 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006444 return false;
6445
Arman Uguray4117ed72015-03-23 15:57:14 -07006446 /* Make sure that the data is correctly formatted. */
6447 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6448 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006449
Szymon Janc9c9db782016-09-18 12:50:06 +02006450 if (data[i + 1] == EIR_FLAGS &&
6451 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006452 return false;
6453
Szymon Janc2bb368702016-09-18 12:50:05 +02006454 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6455 return false;
6456
6457 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6458 return false;
6459
6460 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6461 return false;
6462
6463 if (data[i + 1] == EIR_APPEARANCE &&
6464 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006465 return false;
6466
Arman Uguray24b4f382015-03-23 15:57:12 -07006467 /* If the current field length would exceed the total data
6468 * length, then it's invalid.
6469 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006470 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006471 return false;
6472 }
6473
6474 return true;
6475}
6476
Arman Uguray24b4f382015-03-23 15:57:12 -07006477static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6478 u16 opcode)
6479{
6480 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006481 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006482 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006483 struct adv_info *adv_instance, *n;
6484 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006485
6486 BT_DBG("status %d", status);
6487
6488 hci_dev_lock(hdev);
6489
6490 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6491
Florian Grandelfffd38b2015-06-18 03:16:47 +02006492 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6493 if (!adv_instance->pending)
6494 continue;
6495
6496 if (!status) {
6497 adv_instance->pending = false;
6498 continue;
6499 }
6500
6501 instance = adv_instance->instance;
6502
6503 if (hdev->cur_adv_instance == instance)
6504 cancel_adv_timeout(hdev);
6505
6506 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006507 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006508 }
6509
6510 if (!cmd)
6511 goto unlock;
6512
Florian Grandelfffd38b2015-06-18 03:16:47 +02006513 cp = cmd->param;
6514 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006515
6516 if (status)
6517 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6518 mgmt_status(status));
6519 else
6520 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6521 mgmt_status(status), &rp, sizeof(rp));
6522
6523 mgmt_pending_remove(cmd);
6524
6525unlock:
6526 hci_dev_unlock(hdev);
6527}
6528
6529static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6530 void *data, u16 data_len)
6531{
6532 struct mgmt_cp_add_advertising *cp = data;
6533 struct mgmt_rp_add_advertising rp;
6534 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006535 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006536 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006537 u16 timeout, duration;
6538 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6539 u8 schedule_instance = 0;
6540 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006541 int err;
6542 struct mgmt_pending_cmd *cmd;
6543 struct hci_request req;
6544
6545 BT_DBG("%s", hdev->name);
6546
6547 status = mgmt_le_support(hdev);
6548 if (status)
6549 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6550 status);
6551
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006552 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6553 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6554 MGMT_STATUS_INVALID_PARAMS);
6555
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006556 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6557 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6558 MGMT_STATUS_INVALID_PARAMS);
6559
Arman Uguray24b4f382015-03-23 15:57:12 -07006560 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006561 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006562 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006563
Florian Grandelfffd38b2015-06-18 03:16:47 +02006564 /* The current implementation only supports a subset of the specified
6565 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006566 */
6567 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006568 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006569 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6570 MGMT_STATUS_INVALID_PARAMS);
6571
6572 hci_dev_lock(hdev);
6573
Arman Uguray912098a2015-03-23 15:57:15 -07006574 if (timeout && !hdev_is_powered(hdev)) {
6575 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6576 MGMT_STATUS_REJECTED);
6577 goto unlock;
6578 }
6579
Arman Uguray24b4f382015-03-23 15:57:12 -07006580 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006581 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006582 pending_find(MGMT_OP_SET_LE, hdev)) {
6583 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6584 MGMT_STATUS_BUSY);
6585 goto unlock;
6586 }
6587
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006588 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
6589 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006590 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006591 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6592 MGMT_STATUS_INVALID_PARAMS);
6593 goto unlock;
6594 }
6595
Florian Grandelfffd38b2015-06-18 03:16:47 +02006596 err = hci_add_adv_instance(hdev, cp->instance, flags,
6597 cp->adv_data_len, cp->data,
6598 cp->scan_rsp_len,
6599 cp->data + cp->adv_data_len,
6600 timeout, duration);
6601 if (err < 0) {
6602 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6603 MGMT_STATUS_FAILED);
6604 goto unlock;
6605 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006606
Florian Grandelfffd38b2015-06-18 03:16:47 +02006607 /* Only trigger an advertising added event if a new instance was
6608 * actually added.
6609 */
6610 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006611 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006612
Florian Grandelfffd38b2015-06-18 03:16:47 +02006613 if (hdev->cur_adv_instance == cp->instance) {
6614 /* If the currently advertised instance is being changed then
6615 * cancel the current advertising and schedule the next
6616 * instance. If there is only one instance then the overridden
6617 * advertising data will be visible right away.
6618 */
6619 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006620
Florian Grandelfffd38b2015-06-18 03:16:47 +02006621 next_instance = hci_get_next_instance(hdev, cp->instance);
6622 if (next_instance)
6623 schedule_instance = next_instance->instance;
6624 } else if (!hdev->adv_instance_timeout) {
6625 /* Immediately advertise the new instance if no other
6626 * instance is currently being advertised.
6627 */
6628 schedule_instance = cp->instance;
6629 }
Arman Uguray912098a2015-03-23 15:57:15 -07006630
Florian Grandelfffd38b2015-06-18 03:16:47 +02006631 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6632 * there is no instance to be advertised then we have no HCI
6633 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006634 */
6635 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006636 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6637 !schedule_instance) {
6638 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006639 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6640 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6641 goto unlock;
6642 }
6643
6644 /* We're good to go, update advertising data, parameters, and start
6645 * advertising.
6646 */
6647 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6648 data_len);
6649 if (!cmd) {
6650 err = -ENOMEM;
6651 goto unlock;
6652 }
6653
6654 hci_req_init(&req, hdev);
6655
Johan Hedbergf2252572015-11-18 12:49:20 +02006656 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006657
Florian Grandelfffd38b2015-06-18 03:16:47 +02006658 if (!err)
6659 err = hci_req_run(&req, add_advertising_complete);
6660
Arman Uguray24b4f382015-03-23 15:57:12 -07006661 if (err < 0)
6662 mgmt_pending_remove(cmd);
6663
6664unlock:
6665 hci_dev_unlock(hdev);
6666
6667 return err;
6668}
6669
Arman Ugurayda9293352015-03-23 15:57:13 -07006670static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6671 u16 opcode)
6672{
6673 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006674 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006675 struct mgmt_rp_remove_advertising rp;
6676
6677 BT_DBG("status %d", status);
6678
6679 hci_dev_lock(hdev);
6680
6681 /* A failure status here only means that we failed to disable
6682 * advertising. Otherwise, the advertising instance has been removed,
6683 * so report success.
6684 */
6685 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6686 if (!cmd)
6687 goto unlock;
6688
Florian Grandel01948332015-06-18 03:16:48 +02006689 cp = cmd->param;
6690 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006691
6692 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6693 &rp, sizeof(rp));
6694 mgmt_pending_remove(cmd);
6695
6696unlock:
6697 hci_dev_unlock(hdev);
6698}
6699
6700static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6701 void *data, u16 data_len)
6702{
6703 struct mgmt_cp_remove_advertising *cp = data;
6704 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006705 struct mgmt_pending_cmd *cmd;
6706 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006707 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006708
6709 BT_DBG("%s", hdev->name);
6710
Arman Ugurayda9293352015-03-23 15:57:13 -07006711 hci_dev_lock(hdev);
6712
Johan Hedberg952497b2015-06-18 21:05:31 +03006713 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006714 err = mgmt_cmd_status(sk, hdev->id,
6715 MGMT_OP_REMOVE_ADVERTISING,
6716 MGMT_STATUS_INVALID_PARAMS);
6717 goto unlock;
6718 }
6719
Arman Ugurayda9293352015-03-23 15:57:13 -07006720 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6721 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6722 pending_find(MGMT_OP_SET_LE, hdev)) {
6723 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6724 MGMT_STATUS_BUSY);
6725 goto unlock;
6726 }
6727
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006728 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006729 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6730 MGMT_STATUS_INVALID_PARAMS);
6731 goto unlock;
6732 }
6733
Florian Grandel01948332015-06-18 03:16:48 +02006734 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006735
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006736 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006737
Florian Grandel01948332015-06-18 03:16:48 +02006738 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006739 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006740
Florian Grandel01948332015-06-18 03:16:48 +02006741 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6742 * flag is set or the device isn't powered then we have no HCI
6743 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006744 */
Florian Grandel01948332015-06-18 03:16:48 +02006745 if (skb_queue_empty(&req.cmd_q) ||
6746 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006747 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05306748 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02006749 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006750 err = mgmt_cmd_complete(sk, hdev->id,
6751 MGMT_OP_REMOVE_ADVERTISING,
6752 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6753 goto unlock;
6754 }
6755
6756 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6757 data_len);
6758 if (!cmd) {
6759 err = -ENOMEM;
6760 goto unlock;
6761 }
6762
Arman Ugurayda9293352015-03-23 15:57:13 -07006763 err = hci_req_run(&req, remove_advertising_complete);
6764 if (err < 0)
6765 mgmt_pending_remove(cmd);
6766
6767unlock:
6768 hci_dev_unlock(hdev);
6769
6770 return err;
6771}
6772
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006773static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6774 void *data, u16 data_len)
6775{
6776 struct mgmt_cp_get_adv_size_info *cp = data;
6777 struct mgmt_rp_get_adv_size_info rp;
6778 u32 flags, supported_flags;
6779 int err;
6780
6781 BT_DBG("%s", hdev->name);
6782
6783 if (!lmp_le_capable(hdev))
6784 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6785 MGMT_STATUS_REJECTED);
6786
6787 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6788 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6789 MGMT_STATUS_INVALID_PARAMS);
6790
6791 flags = __le32_to_cpu(cp->flags);
6792
6793 /* The current implementation only supports a subset of the specified
6794 * flags.
6795 */
6796 supported_flags = get_supported_adv_flags(hdev);
6797 if (flags & ~supported_flags)
6798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6799 MGMT_STATUS_INVALID_PARAMS);
6800
6801 rp.instance = cp->instance;
6802 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006803 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
6804 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006805
6806 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6807 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6808
6809 return err;
6810}
6811
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006812static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006813 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006814 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006815 HCI_MGMT_NO_HDEV |
6816 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006817 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006818 HCI_MGMT_NO_HDEV |
6819 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006820 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006821 HCI_MGMT_NO_HDEV |
6822 HCI_MGMT_UNTRUSTED },
6823 { read_controller_info, MGMT_READ_INFO_SIZE,
6824 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006825 { set_powered, MGMT_SETTING_SIZE },
6826 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6827 { set_connectable, MGMT_SETTING_SIZE },
6828 { set_fast_connectable, MGMT_SETTING_SIZE },
6829 { set_bondable, MGMT_SETTING_SIZE },
6830 { set_link_security, MGMT_SETTING_SIZE },
6831 { set_ssp, MGMT_SETTING_SIZE },
6832 { set_hs, MGMT_SETTING_SIZE },
6833 { set_le, MGMT_SETTING_SIZE },
6834 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6835 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6836 { add_uuid, MGMT_ADD_UUID_SIZE },
6837 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006838 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6839 HCI_MGMT_VAR_LEN },
6840 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6841 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006842 { disconnect, MGMT_DISCONNECT_SIZE },
6843 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6844 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6845 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6846 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6847 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6848 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6849 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6850 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6851 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6852 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6853 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006854 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6855 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6856 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006857 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6858 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6859 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6860 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6861 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6862 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6863 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6864 { set_advertising, MGMT_SETTING_SIZE },
6865 { set_bredr, MGMT_SETTING_SIZE },
6866 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6867 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6868 { set_secure_conn, MGMT_SETTING_SIZE },
6869 { set_debug_keys, MGMT_SETTING_SIZE },
6870 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006871 { load_irks, MGMT_LOAD_IRKS_SIZE,
6872 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006873 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6874 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6875 { add_device, MGMT_ADD_DEVICE_SIZE },
6876 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006877 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6878 HCI_MGMT_VAR_LEN },
6879 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006880 HCI_MGMT_NO_HDEV |
6881 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006882 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006883 HCI_MGMT_UNCONFIGURED |
6884 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006885 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6886 HCI_MGMT_UNCONFIGURED },
6887 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6888 HCI_MGMT_UNCONFIGURED },
6889 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6890 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006891 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006892 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006893 HCI_MGMT_NO_HDEV |
6894 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006895 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006896 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6897 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006898 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006899 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006900 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006901 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6902 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006903 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05306904 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05306905 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006906};
6907
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006908void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006909{
Marcel Holtmannced85542015-03-14 19:27:56 -07006910 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006911
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006912 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6913 return;
6914
Marcel Holtmannf9207332015-03-14 19:27:55 -07006915 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006916 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006917 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6918 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6919 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006920 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006921 } else {
6922 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6923 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006924 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006925 }
6926 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006927 case HCI_AMP:
6928 ev.type = 0x02;
6929 break;
6930 default:
6931 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006932 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006933
6934 ev.bus = hdev->bus;
6935
6936 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6937 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006938}
6939
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006940void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006941{
Marcel Holtmannced85542015-03-14 19:27:56 -07006942 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006943 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006944
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006945 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6946 return;
6947
Marcel Holtmannf9207332015-03-14 19:27:55 -07006948 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006949 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006950 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006951
Marcel Holtmannf9207332015-03-14 19:27:55 -07006952 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6953 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6954 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006955 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006956 } else {
6957 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6958 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006959 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006960 }
6961 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006962 case HCI_AMP:
6963 ev.type = 0x02;
6964 break;
6965 default:
6966 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006967 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006968
6969 ev.bus = hdev->bus;
6970
6971 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6972 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006973}
6974
Andre Guedes6046dc32014-02-26 20:21:51 -03006975/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006976static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006977{
6978 struct hci_conn_params *p;
6979
6980 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006981 /* Needed for AUTO_OFF case where might not "really"
6982 * have been powered off.
6983 */
6984 list_del_init(&p->action);
6985
6986 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006987 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006988 case HCI_AUTO_CONN_ALWAYS:
6989 list_add(&p->action, &hdev->pend_le_conns);
6990 break;
6991 case HCI_AUTO_CONN_REPORT:
6992 list_add(&p->action, &hdev->pend_le_reports);
6993 break;
6994 default:
6995 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006996 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006997 }
6998}
6999
Johan Hedberg2ff13892015-11-25 16:15:44 +02007000void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007001{
7002 struct cmd_lookup match = { NULL, hdev };
7003
Johan Hedberg2ff13892015-11-25 16:15:44 +02007004 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007005
Johan Hedberg2ff13892015-11-25 16:15:44 +02007006 hci_dev_lock(hdev);
7007
7008 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007009 restart_le_actions(hdev);
7010 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007011 }
7012
Johan Hedberg229ab392013-03-15 17:06:53 -05007013 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7014
7015 new_settings(hdev, match.sk);
7016
Johan Hedberg229ab392013-03-15 17:06:53 -05007017 if (match.sk)
7018 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007019
7020 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007021}
7022
Johan Hedberg2ff13892015-11-25 16:15:44 +02007023void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007024{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007025 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007026 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007027
Johan Hedberg229ab392013-03-15 17:06:53 -05007028 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007029
7030 /* If the power off is because of hdev unregistration let
7031 * use the appropriate INVALID_INDEX status. Otherwise use
7032 * NOT_POWERED. We cover both scenarios here since later in
7033 * mgmt_index_removed() any hci_conn callbacks will have already
7034 * been triggered, potentially causing misleading DISCONNECTED
7035 * status responses.
7036 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007037 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007038 status = MGMT_STATUS_INVALID_INDEX;
7039 else
7040 status = MGMT_STATUS_NOT_POWERED;
7041
7042 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007043
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007044 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007045 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7046 zero_cod, sizeof(zero_cod),
7047 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007048 ext_info_changed(hdev, NULL);
7049 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007050
Johan Hedberg2ff13892015-11-25 16:15:44 +02007051 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007052
7053 if (match.sk)
7054 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007055}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007056
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007057void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007058{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007059 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007060 u8 status;
7061
Johan Hedberg333ae952015-03-17 13:48:47 +02007062 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007063 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007064 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007065
7066 if (err == -ERFKILL)
7067 status = MGMT_STATUS_RFKILLED;
7068 else
7069 status = MGMT_STATUS_FAILED;
7070
Johan Hedberga69e8372015-03-06 21:08:53 +02007071 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007072
7073 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007074}
7075
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007076void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7077 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007078{
Johan Hedberg86742e12011-11-07 23:13:38 +02007079 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007080
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007081 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007082
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007083 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007084 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007085 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007086 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007087 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007088 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007089
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007090 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007091}
Johan Hedbergf7520542011-01-20 12:34:39 +02007092
Johan Hedbergd7b25452014-05-23 13:19:53 +03007093static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7094{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007095 switch (ltk->type) {
7096 case SMP_LTK:
7097 case SMP_LTK_SLAVE:
7098 if (ltk->authenticated)
7099 return MGMT_LTK_AUTHENTICATED;
7100 return MGMT_LTK_UNAUTHENTICATED;
7101 case SMP_LTK_P256:
7102 if (ltk->authenticated)
7103 return MGMT_LTK_P256_AUTH;
7104 return MGMT_LTK_P256_UNAUTH;
7105 case SMP_LTK_P256_DEBUG:
7106 return MGMT_LTK_P256_DEBUG;
7107 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007108
7109 return MGMT_LTK_UNAUTHENTICATED;
7110}
7111
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007112void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007113{
7114 struct mgmt_ev_new_long_term_key ev;
7115
7116 memset(&ev, 0, sizeof(ev));
7117
Marcel Holtmann5192d302014-02-19 17:11:58 -08007118 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007119 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007120 * to store long term keys. Their addresses will change the
7121 * next time around.
7122 *
7123 * Only when a remote device provides an identity address
7124 * make sure the long term key is stored. If the remote
7125 * identity is known, the long term keys are internally
7126 * mapped to the identity address. So allow static random
7127 * and public addresses here.
7128 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007129 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7130 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7131 ev.store_hint = 0x00;
7132 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007133 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007134
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007135 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007136 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007137 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007138 ev.key.enc_size = key->enc_size;
7139 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007140 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007141
Johan Hedberg2ceba532014-06-16 19:25:16 +03007142 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007143 ev.key.master = 1;
7144
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007145 /* Make sure we copy only the significant bytes based on the
7146 * encryption key size, and set the rest of the value to zeroes.
7147 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007148 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007149 memset(ev.key.val + key->enc_size, 0,
7150 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007151
Marcel Holtmann083368f2013-10-15 14:26:29 -07007152 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007153}
7154
Johan Hedbergcad20c22015-10-12 13:36:19 +02007155void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007156{
7157 struct mgmt_ev_new_irk ev;
7158
7159 memset(&ev, 0, sizeof(ev));
7160
Johan Hedbergcad20c22015-10-12 13:36:19 +02007161 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007162
Johan Hedberg95fbac82014-02-19 15:18:31 +02007163 bacpy(&ev.rpa, &irk->rpa);
7164 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7165 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7166 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7167
7168 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7169}
7170
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007171void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7172 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007173{
7174 struct mgmt_ev_new_csrk ev;
7175
7176 memset(&ev, 0, sizeof(ev));
7177
7178 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007179 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007180 * to store signature resolving keys. Their addresses will change
7181 * the next time around.
7182 *
7183 * Only when a remote device provides an identity address
7184 * make sure the signature resolving key is stored. So allow
7185 * static random and public addresses here.
7186 */
7187 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7188 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7189 ev.store_hint = 0x00;
7190 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007191 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007192
7193 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7194 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007195 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007196 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7197
7198 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7199}
7200
Andre Guedesffb5a8272014-07-01 18:10:11 -03007201void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007202 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7203 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007204{
7205 struct mgmt_ev_new_conn_param ev;
7206
Johan Hedbergc103aea2014-07-02 17:37:34 +03007207 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7208 return;
7209
Andre Guedesffb5a8272014-07-01 18:10:11 -03007210 memset(&ev, 0, sizeof(ev));
7211 bacpy(&ev.addr.bdaddr, bdaddr);
7212 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007213 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007214 ev.min_interval = cpu_to_le16(min_interval);
7215 ev.max_interval = cpu_to_le16(max_interval);
7216 ev.latency = cpu_to_le16(latency);
7217 ev.timeout = cpu_to_le16(timeout);
7218
7219 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7220}
7221
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007222void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7223 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007224{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007225 char buf[512];
7226 struct mgmt_ev_device_connected *ev = (void *) buf;
7227 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007228
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007229 bacpy(&ev->addr.bdaddr, &conn->dst);
7230 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007231
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007232 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007233
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007234 /* We must ensure that the EIR Data fields are ordered and
7235 * unique. Keep it simple for now and avoid the problem by not
7236 * adding any BR/EDR data to the LE adv.
7237 */
7238 if (conn->le_adv_data_len > 0) {
7239 memcpy(&ev->eir[eir_len],
7240 conn->le_adv_data, conn->le_adv_data_len);
7241 eir_len = conn->le_adv_data_len;
7242 } else {
7243 if (name_len > 0)
7244 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7245 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007246
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007247 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007248 eir_len = eir_append_data(ev->eir, eir_len,
7249 EIR_CLASS_OF_DEV,
7250 conn->dev_class, 3);
7251 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007252
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007253 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007254
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007255 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7256 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007257}
7258
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007259static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007260{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007261 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007262
Johan Hedbergf5818c22014-12-05 13:36:02 +02007263 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007264
7265 *sk = cmd->sk;
7266 sock_hold(*sk);
7267
Johan Hedberga664b5b2011-02-19 12:06:02 -03007268 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007269}
7270
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007271static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007272{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007273 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007274 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007275
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007276 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7277
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007278 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007279 mgmt_pending_remove(cmd);
7280}
7281
Johan Hedberg84c61d92014-08-01 11:13:30 +03007282bool mgmt_powering_down(struct hci_dev *hdev)
7283{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007284 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007285 struct mgmt_mode *cp;
7286
Johan Hedberg333ae952015-03-17 13:48:47 +02007287 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007288 if (!cmd)
7289 return false;
7290
7291 cp = cmd->param;
7292 if (!cp->val)
7293 return true;
7294
7295 return false;
7296}
7297
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007298void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007299 u8 link_type, u8 addr_type, u8 reason,
7300 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007301{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007302 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007303 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007304
Johan Hedberg84c61d92014-08-01 11:13:30 +03007305 /* The connection is still in hci_conn_hash so test for 1
7306 * instead of 0 to know if this is the last one.
7307 */
7308 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7309 cancel_delayed_work(&hdev->power_off);
7310 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007311 }
7312
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007313 if (!mgmt_connected)
7314 return;
7315
Andre Guedes57eb7762013-10-30 19:01:41 -03007316 if (link_type != ACL_LINK && link_type != LE_LINK)
7317 return;
7318
Johan Hedberg744cf192011-11-08 20:40:14 +02007319 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007320
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007321 bacpy(&ev.addr.bdaddr, bdaddr);
7322 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7323 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007324
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007325 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007326
7327 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007328 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007329
Johan Hedberg124f6e32012-02-09 13:50:12 +02007330 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007331 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007332}
7333
Marcel Holtmann78929242013-10-06 23:55:47 -07007334void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7335 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007336{
Andre Guedes3655bba2013-10-30 19:01:40 -03007337 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7338 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007339 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007340
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007341 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7342 hdev);
7343
Johan Hedberg333ae952015-03-17 13:48:47 +02007344 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007345 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007346 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007347
Andre Guedes3655bba2013-10-30 19:01:40 -03007348 cp = cmd->param;
7349
7350 if (bacmp(bdaddr, &cp->addr.bdaddr))
7351 return;
7352
7353 if (cp->addr.type != bdaddr_type)
7354 return;
7355
Johan Hedbergf5818c22014-12-05 13:36:02 +02007356 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007357 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007358}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007359
Marcel Holtmann445608d2013-10-06 23:55:48 -07007360void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7361 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007362{
7363 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007364
Johan Hedberg84c61d92014-08-01 11:13:30 +03007365 /* The connection is still in hci_conn_hash so test for 1
7366 * instead of 0 to know if this is the last one.
7367 */
7368 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7369 cancel_delayed_work(&hdev->power_off);
7370 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007371 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007372
Johan Hedberg4c659c32011-11-07 23:13:39 +02007373 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007374 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007375 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007376
Marcel Holtmann445608d2013-10-06 23:55:48 -07007377 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007378}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007379
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007380void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007381{
7382 struct mgmt_ev_pin_code_request ev;
7383
Johan Hedbergd8457692012-02-17 14:24:57 +02007384 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007385 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007386 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007387
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007388 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007389}
7390
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007391void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7392 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007393{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007394 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007395
Johan Hedberg333ae952015-03-17 13:48:47 +02007396 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007397 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007398 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007399
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007400 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007401 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007402}
7403
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007404void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7405 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007406{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007407 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007408
Johan Hedberg333ae952015-03-17 13:48:47 +02007409 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007410 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007411 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007412
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007413 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007414 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007415}
Johan Hedberga5c29682011-02-19 12:05:57 -03007416
Johan Hedberg744cf192011-11-08 20:40:14 +02007417int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007418 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007419 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007420{
7421 struct mgmt_ev_user_confirm_request ev;
7422
Johan Hedberg744cf192011-11-08 20:40:14 +02007423 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007424
Johan Hedberg272d90d2012-02-09 15:26:12 +02007425 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007426 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007427 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007428 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007429
Johan Hedberg744cf192011-11-08 20:40:14 +02007430 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007431 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007432}
7433
Johan Hedberg272d90d2012-02-09 15:26:12 +02007434int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007435 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007436{
7437 struct mgmt_ev_user_passkey_request ev;
7438
7439 BT_DBG("%s", hdev->name);
7440
Johan Hedberg272d90d2012-02-09 15:26:12 +02007441 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007442 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007443
7444 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007445 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007446}
7447
Brian Gix0df4c182011-11-16 13:53:13 -08007448static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007449 u8 link_type, u8 addr_type, u8 status,
7450 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007451{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007452 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007453
Johan Hedberg333ae952015-03-17 13:48:47 +02007454 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007455 if (!cmd)
7456 return -ENOENT;
7457
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007458 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007459 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007460
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007461 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007462}
7463
Johan Hedberg744cf192011-11-08 20:40:14 +02007464int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007465 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007466{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007467 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007468 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007469}
7470
Johan Hedberg272d90d2012-02-09 15:26:12 +02007471int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007472 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007473{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007474 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007475 status,
7476 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007477}
Johan Hedberg2a611692011-02-19 12:06:00 -03007478
Brian Gix604086b2011-11-23 08:28:33 -08007479int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007480 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007481{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007482 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007483 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007484}
7485
Johan Hedberg272d90d2012-02-09 15:26:12 +02007486int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007487 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007488{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007489 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007490 status,
7491 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007492}
7493
Johan Hedberg92a25252012-09-06 18:39:26 +03007494int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7495 u8 link_type, u8 addr_type, u32 passkey,
7496 u8 entered)
7497{
7498 struct mgmt_ev_passkey_notify ev;
7499
7500 BT_DBG("%s", hdev->name);
7501
7502 bacpy(&ev.addr.bdaddr, bdaddr);
7503 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7504 ev.passkey = __cpu_to_le32(passkey);
7505 ev.entered = entered;
7506
7507 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7508}
7509
Johan Hedberge1e930f2014-09-08 17:09:49 -07007510void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007511{
7512 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007513 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007514 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007515
Johan Hedberge1e930f2014-09-08 17:09:49 -07007516 bacpy(&ev.addr.bdaddr, &conn->dst);
7517 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7518 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007519
Johan Hedberge1e930f2014-09-08 17:09:49 -07007520 cmd = find_pairing(conn);
7521
7522 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7523 cmd ? cmd->sk : NULL);
7524
Johan Hedberga511b352014-12-11 21:45:45 +02007525 if (cmd) {
7526 cmd->cmd_complete(cmd, status);
7527 mgmt_pending_remove(cmd);
7528 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007529}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007530
Marcel Holtmann464996a2013-10-15 14:26:24 -07007531void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007532{
7533 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007534 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007535
7536 if (status) {
7537 u8 mgmt_err = mgmt_status(status);
7538 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007539 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007540 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007541 }
7542
Marcel Holtmann464996a2013-10-15 14:26:24 -07007543 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007544 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007545 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007546 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007547
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007548 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007549 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007550
Johan Hedberg47990ea2012-02-22 11:58:37 +02007551 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007552 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007553
7554 if (match.sk)
7555 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007556}
7557
Johan Hedberg890ea892013-03-15 17:06:52 -05007558static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007559{
Johan Hedberg890ea892013-03-15 17:06:52 -05007560 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007561 struct hci_cp_write_eir cp;
7562
Johan Hedberg976eb202012-10-24 21:12:01 +03007563 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007564 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007565
Johan Hedbergc80da272012-02-22 15:38:48 +02007566 memset(hdev->eir, 0, sizeof(hdev->eir));
7567
Johan Hedbergcacaf522012-02-21 00:52:42 +02007568 memset(&cp, 0, sizeof(cp));
7569
Johan Hedberg890ea892013-03-15 17:06:52 -05007570 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007571}
7572
Marcel Holtmann3e248562013-10-15 14:26:25 -07007573void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007574{
7575 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007576 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007577 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007578
7579 if (status) {
7580 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007581
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007582 if (enable && hci_dev_test_and_clear_flag(hdev,
7583 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007584 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007585 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007586 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007587
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007588 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7589 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007590 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007591 }
7592
7593 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007594 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007595 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007596 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007597 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007598 changed = hci_dev_test_and_clear_flag(hdev,
7599 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007600 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007601 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007602 }
7603
7604 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7605
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007606 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007607 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007608
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007609 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007610 sock_put(match.sk);
7611
Johan Hedberg890ea892013-03-15 17:06:52 -05007612 hci_req_init(&req, hdev);
7613
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007614 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7615 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007616 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7617 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007618 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007619 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007620 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007621 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007622
7623 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007624}
7625
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007626static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007627{
7628 struct cmd_lookup *match = data;
7629
Johan Hedberg90e70452012-02-23 23:09:40 +02007630 if (match->sk == NULL) {
7631 match->sk = cmd->sk;
7632 sock_hold(match->sk);
7633 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007634}
7635
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007636void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7637 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007638{
Johan Hedberg90e70452012-02-23 23:09:40 +02007639 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007640
Johan Hedberg92da6092013-03-15 17:06:55 -05007641 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7642 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7643 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007644
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007645 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007646 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7647 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007648 ext_info_changed(hdev, NULL);
7649 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007650
7651 if (match.sk)
7652 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007653}
7654
Marcel Holtmann7667da32013-10-15 14:26:27 -07007655void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007656{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007657 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007658 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007659
Johan Hedberg13928972013-03-15 17:07:00 -05007660 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007661 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007662
7663 memset(&ev, 0, sizeof(ev));
7664 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007665 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007666
Johan Hedberg333ae952015-03-17 13:48:47 +02007667 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007668 if (!cmd) {
7669 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007670
Johan Hedberg13928972013-03-15 17:07:00 -05007671 /* If this is a HCI command related to powering on the
7672 * HCI dev don't send any mgmt signals.
7673 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007674 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007675 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007676 }
7677
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007678 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7679 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007680 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007681}
Szymon Jancc35938b2011-03-22 13:12:21 +01007682
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007683static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7684{
7685 int i;
7686
7687 for (i = 0; i < uuid_count; i++) {
7688 if (!memcmp(uuid, uuids[i], 16))
7689 return true;
7690 }
7691
7692 return false;
7693}
7694
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007695static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7696{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007697 u16 parsed = 0;
7698
7699 while (parsed < eir_len) {
7700 u8 field_len = eir[0];
7701 u8 uuid[16];
7702 int i;
7703
7704 if (field_len == 0)
7705 break;
7706
7707 if (eir_len - parsed < field_len + 1)
7708 break;
7709
7710 switch (eir[1]) {
7711 case EIR_UUID16_ALL:
7712 case EIR_UUID16_SOME:
7713 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007714 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007715 uuid[13] = eir[i + 3];
7716 uuid[12] = eir[i + 2];
7717 if (has_uuid(uuid, uuid_count, uuids))
7718 return true;
7719 }
7720 break;
7721 case EIR_UUID32_ALL:
7722 case EIR_UUID32_SOME:
7723 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007724 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007725 uuid[15] = eir[i + 5];
7726 uuid[14] = eir[i + 4];
7727 uuid[13] = eir[i + 3];
7728 uuid[12] = eir[i + 2];
7729 if (has_uuid(uuid, uuid_count, uuids))
7730 return true;
7731 }
7732 break;
7733 case EIR_UUID128_ALL:
7734 case EIR_UUID128_SOME:
7735 for (i = 0; i + 17 <= field_len; i += 16) {
7736 memcpy(uuid, eir + i + 2, 16);
7737 if (has_uuid(uuid, uuid_count, uuids))
7738 return true;
7739 }
7740 break;
7741 }
7742
7743 parsed += field_len + 1;
7744 eir += field_len + 1;
7745 }
7746
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007747 return false;
7748}
7749
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007750static void restart_le_scan(struct hci_dev *hdev)
7751{
7752 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007753 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007754 return;
7755
7756 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7757 hdev->discovery.scan_start +
7758 hdev->discovery.scan_duration))
7759 return;
7760
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007761 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007762 DISCOV_LE_RESTART_DELAY);
7763}
7764
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007765static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7766 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7767{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007768 /* If a RSSI threshold has been specified, and
7769 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7770 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7771 * is set, let it through for further processing, as we might need to
7772 * restart the scan.
7773 *
7774 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7775 * the results are also dropped.
7776 */
7777 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7778 (rssi == HCI_RSSI_INVALID ||
7779 (rssi < hdev->discovery.rssi &&
7780 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7781 return false;
7782
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007783 if (hdev->discovery.uuid_count != 0) {
7784 /* If a list of UUIDs is provided in filter, results with no
7785 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007786 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007787 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7788 hdev->discovery.uuids) &&
7789 !eir_has_uuids(scan_rsp, scan_rsp_len,
7790 hdev->discovery.uuid_count,
7791 hdev->discovery.uuids))
7792 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007793 }
7794
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007795 /* If duplicate filtering does not report RSSI changes, then restart
7796 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007797 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007798 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7799 restart_le_scan(hdev);
7800
7801 /* Validate RSSI value against the RSSI threshold once more. */
7802 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7803 rssi < hdev->discovery.rssi)
7804 return false;
7805 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007806
7807 return true;
7808}
7809
Marcel Holtmann901801b2013-10-06 23:55:51 -07007810void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007811 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7812 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007813{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007814 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007815 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007816 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007817
Johan Hedberg75ce2082014-07-02 22:42:01 +03007818 /* Don't send events for a non-kernel initiated discovery. With
7819 * LE one exception is if we have pend_le_reports > 0 in which
7820 * case we're doing passive scanning and want these events.
7821 */
7822 if (!hci_discovery_active(hdev)) {
7823 if (link_type == ACL_LINK)
7824 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007825 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007826 return;
7827 }
Andre Guedes12602d02013-04-30 15:29:40 -03007828
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007829 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007830 /* We are using service discovery */
7831 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7832 scan_rsp_len))
7833 return;
7834 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007835
Johan Hedberg78b781c2016-01-05 13:19:32 +02007836 if (hdev->discovery.limited) {
7837 /* Check for limited discoverable bit */
7838 if (dev_class) {
7839 if (!(dev_class[1] & 0x20))
7840 return;
7841 } else {
7842 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7843 if (!flags || !(flags[0] & LE_AD_LIMITED))
7844 return;
7845 }
7846 }
7847
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007848 /* Make sure that the buffer is big enough. The 5 extra bytes
7849 * are for the potential CoD field.
7850 */
7851 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007852 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007853
Johan Hedberg1dc06092012-01-15 21:01:23 +02007854 memset(buf, 0, sizeof(buf));
7855
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007856 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7857 * RSSI value was reported as 0 when not available. This behavior
7858 * is kept when using device discovery. This is required for full
7859 * backwards compatibility with the API.
7860 *
7861 * However when using service discovery, the value 127 will be
7862 * returned when the RSSI is not available.
7863 */
Szymon Janc91200e92015-01-22 16:57:05 +01007864 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7865 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007866 rssi = 0;
7867
Johan Hedberg841c5642014-07-07 12:45:54 +03007868 bacpy(&ev->addr.bdaddr, bdaddr);
7869 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007870 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007871 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007872
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007873 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007874 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007875 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007876
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007877 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7878 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007879 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007880 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007881
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007882 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007883 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007884 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007885
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007886 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7887 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007888
Marcel Holtmann901801b2013-10-06 23:55:51 -07007889 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007890}
Johan Hedberga88a9652011-03-30 13:18:12 +03007891
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007892void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7893 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007894{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007895 struct mgmt_ev_device_found *ev;
7896 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7897 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007898
Johan Hedbergb644ba32012-01-17 21:48:47 +02007899 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007900
Johan Hedbergb644ba32012-01-17 21:48:47 +02007901 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007902
Johan Hedbergb644ba32012-01-17 21:48:47 +02007903 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007904 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007905 ev->rssi = rssi;
7906
7907 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007908 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007909
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007910 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007911
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007912 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007913}
Johan Hedberg314b2382011-04-27 10:29:57 -04007914
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007915void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007916{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007917 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007918
Andre Guedes343fb142011-11-22 17:14:19 -03007919 BT_DBG("%s discovering %u", hdev->name, discovering);
7920
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007921 memset(&ev, 0, sizeof(ev));
7922 ev.type = hdev->discovery.type;
7923 ev.discovering = discovering;
7924
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007925 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007926}
Antti Julku5e762442011-08-25 16:48:02 +03007927
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007928static struct hci_mgmt_chan chan = {
7929 .channel = HCI_CHANNEL_CONTROL,
7930 .handler_count = ARRAY_SIZE(mgmt_handlers),
7931 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007932 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007933};
7934
7935int mgmt_init(void)
7936{
7937 return hci_mgmt_chan_register(&chan);
7938}
7939
7940void mgmt_exit(void)
7941{
7942 hci_mgmt_chan_unregister(&chan);
7943}