blob: c283f0364c0f8061b2221c33a76fa4a42526bb49 [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;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001850 hci_req_init(&req, hdev);
Jaganath Kanakkasserya0fb3722018-07-19 17:09:42 +05301851 if (ext_adv_capable(hdev)) {
1852 int err;
1853
1854 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1855 if (!err)
1856 __hci_req_update_scan_rsp_data(&req, 0x00);
1857 } else {
1858 __hci_req_update_adv_data(&req, 0x00);
1859 __hci_req_update_scan_rsp_data(&req, 0x00);
1860 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001861 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001862 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001863 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301864
1865unlock:
1866 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001867}
1868
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001870{
1871 struct mgmt_mode *cp = data;
1872 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001873 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001874 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001875 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001876 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001877
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001878 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001879
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001880 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001881 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1882 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001883
Johan Hedberga7e80f22013-01-09 16:05:19 +02001884 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001885 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1886 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001887
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001888 /* Bluetooth single mode LE only controllers or dual-mode
1889 * controllers configured as LE only devices, do not allow
1890 * switching LE off. These have either LE enabled explicitly
1891 * or BR/EDR has been previously switched off.
1892 *
1893 * When trying to enable an already enabled LE, then gracefully
1894 * send a positive response. Trying to disable it however will
1895 * result into rejection.
1896 */
1897 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1898 if (cp->val == 0x01)
1899 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1900
Johan Hedberga69e8372015-03-06 21:08:53 +02001901 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1902 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001903 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001904
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001905 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001906
1907 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001908 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001909
Florian Grandel847818d2015-06-18 03:16:46 +02001910 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001911 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001912
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001913 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001914 bool changed = false;
1915
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001916 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001917 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001918 changed = true;
1919 }
1920
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001921 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001922 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001923 changed = true;
1924 }
1925
Johan Hedberg06199cf2012-02-22 16:37:11 +02001926 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1927 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001928 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001929
1930 if (changed)
1931 err = new_settings(hdev, sk);
1932
Johan Hedberg1de028c2012-02-29 19:55:35 -08001933 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001934 }
1935
Johan Hedberg333ae952015-03-17 13:48:47 +02001936 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1937 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001938 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1939 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001940 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001941 }
1942
1943 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1944 if (!cmd) {
1945 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001946 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001947 }
1948
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001949 hci_req_init(&req, hdev);
1950
Johan Hedberg06199cf2012-02-22 16:37:11 +02001951 memset(&hci_cp, 0, sizeof(hci_cp));
1952
1953 if (val) {
1954 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001955 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001956 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001957 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001958 __hci_req_disable_advertising(&req);
Jaganath Kanakkassery45b77492018-07-19 17:09:43 +05301959
1960 if (ext_adv_capable(hdev))
1961 __hci_req_clear_ext_adv_sets(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 }
1963
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001964 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1965 &hci_cp);
1966
1967 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301968 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001969 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001970
Johan Hedberg1de028c2012-02-29 19:55:35 -08001971unlock:
1972 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001973 return err;
1974}
1975
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001976/* This is a helper function to test for pending mgmt commands that can
1977 * cause CoD or EIR HCI commands. We can only allow one such pending
1978 * mgmt command at a time since otherwise we cannot easily track what
1979 * the current values are, will be, and based on that calculate if a new
1980 * HCI command needs to be sent and if yes with what value.
1981 */
1982static bool pending_eir_or_class(struct hci_dev *hdev)
1983{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001984 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001985
1986 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1987 switch (cmd->opcode) {
1988 case MGMT_OP_ADD_UUID:
1989 case MGMT_OP_REMOVE_UUID:
1990 case MGMT_OP_SET_DEV_CLASS:
1991 case MGMT_OP_SET_POWERED:
1992 return true;
1993 }
1994 }
1995
1996 return false;
1997}
1998
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001999static const u8 bluetooth_base_uuid[] = {
2000 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2001 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2002};
2003
2004static u8 get_uuid_size(const u8 *uuid)
2005{
2006 u32 val;
2007
2008 if (memcmp(uuid, bluetooth_base_uuid, 12))
2009 return 128;
2010
2011 val = get_unaligned_le32(&uuid[12]);
2012 if (val > 0xffff)
2013 return 32;
2014
2015 return 16;
2016}
2017
Johan Hedberg92da6092013-03-15 17:06:55 -05002018static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2019{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002020 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002021
2022 hci_dev_lock(hdev);
2023
Johan Hedberg333ae952015-03-17 13:48:47 +02002024 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002025 if (!cmd)
2026 goto unlock;
2027
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002028 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2029 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002030
2031 mgmt_pending_remove(cmd);
2032
2033unlock:
2034 hci_dev_unlock(hdev);
2035}
2036
Marcel Holtmann1904a852015-01-11 13:50:44 -08002037static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002038{
2039 BT_DBG("status 0x%02x", status);
2040
2041 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2042}
2043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002045{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002046 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002047 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002048 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002049 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002050 int err;
2051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002052 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002053
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002054 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002056 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002057 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2058 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002059 goto failed;
2060 }
2061
Andre Guedes92c4c202012-06-07 19:05:44 -03002062 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063 if (!uuid) {
2064 err = -ENOMEM;
2065 goto failed;
2066 }
2067
2068 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002069 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002070 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002071
Johan Hedbergde66aa62013-01-27 00:31:27 +02002072 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002073
Johan Hedberg890ea892013-03-15 17:06:52 -05002074 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002075
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002076 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002077 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002078
Johan Hedberg92da6092013-03-15 17:06:55 -05002079 err = hci_req_run(&req, add_uuid_complete);
2080 if (err < 0) {
2081 if (err != -ENODATA)
2082 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002083
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002084 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2085 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002086 goto failed;
2087 }
2088
2089 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002090 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002091 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002092 goto failed;
2093 }
2094
2095 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002096
2097failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002098 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099 return err;
2100}
2101
Johan Hedberg24b78d02012-02-23 23:24:30 +02002102static bool enable_service_cache(struct hci_dev *hdev)
2103{
2104 if (!hdev_is_powered(hdev))
2105 return false;
2106
Marcel Holtmann238be782015-03-13 02:11:06 -07002107 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002108 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2109 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002110 return true;
2111 }
2112
2113 return false;
2114}
2115
Marcel Holtmann1904a852015-01-11 13:50:44 -08002116static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002117{
2118 BT_DBG("status 0x%02x", status);
2119
2120 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2121}
2122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002123static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002124 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002126 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002127 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002128 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05002130 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002131 int err, found;
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002136
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002137 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002138 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2139 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002140 goto unlock;
2141 }
2142
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002143 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002144 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002145
Johan Hedberg24b78d02012-02-23 23:24:30 +02002146 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002147 err = mgmt_cmd_complete(sk, hdev->id,
2148 MGMT_OP_REMOVE_UUID,
2149 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002150 goto unlock;
2151 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002152
Johan Hedberg9246a862012-02-23 21:33:16 +02002153 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002154 }
2155
2156 found = 0;
2157
Johan Hedberg056341c2013-01-27 00:31:30 +02002158 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002159 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2160 continue;
2161
2162 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002163 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164 found++;
2165 }
2166
2167 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002168 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2169 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002170 goto unlock;
2171 }
2172
Johan Hedberg9246a862012-02-23 21:33:16 +02002173update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002174 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002175
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002176 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002177 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002178
Johan Hedberg92da6092013-03-15 17:06:55 -05002179 err = hci_req_run(&req, remove_uuid_complete);
2180 if (err < 0) {
2181 if (err != -ENODATA)
2182 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002183
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002184 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2185 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002186 goto unlock;
2187 }
2188
2189 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002190 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002191 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002192 goto unlock;
2193 }
2194
2195 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002196
2197unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002198 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002199 return err;
2200}
2201
Marcel Holtmann1904a852015-01-11 13:50:44 -08002202static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002203{
2204 BT_DBG("status 0x%02x", status);
2205
2206 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2207}
2208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002213 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002214 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002215 int err;
2216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002217 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002218
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002219 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002220 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2221 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002222
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002223 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002224
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002225 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002226 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2227 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002228 goto unlock;
2229 }
2230
2231 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002234 goto unlock;
2235 }
2236
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002237 hdev->major_class = cp->major;
2238 hdev->minor_class = cp->minor;
2239
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002240 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002241 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2242 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002243 goto unlock;
2244 }
2245
Johan Hedberg890ea892013-03-15 17:06:52 -05002246 hci_req_init(&req, hdev);
2247
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002248 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002249 hci_dev_unlock(hdev);
2250 cancel_delayed_work_sync(&hdev->service_cache);
2251 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002252 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002253 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002254
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002255 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002256
Johan Hedberg92da6092013-03-15 17:06:55 -05002257 err = hci_req_run(&req, set_class_complete);
2258 if (err < 0) {
2259 if (err != -ENODATA)
2260 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002261
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002262 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2263 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002264 goto unlock;
2265 }
2266
2267 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002268 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002269 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002270 goto unlock;
2271 }
2272
2273 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002274
Johan Hedbergb5235a62012-02-21 14:32:24 +02002275unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002276 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002277 return err;
2278}
2279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002281 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002282{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002284 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2285 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002286 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002287 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002288 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002289
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002290 BT_DBG("request for %s", hdev->name);
2291
2292 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2294 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002295
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002296 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002297 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002298 bt_dev_err(hdev, "load_link_keys: too big key_count value %u",
2299 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002300 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2301 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002302 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002303
Johan Hedberg86742e12011-11-07 23:13:38 +02002304 expected_len = sizeof(*cp) + key_count *
2305 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002306 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002307 bt_dev_err(hdev, "load_link_keys: expected %u bytes, got %u bytes",
2308 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002309 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2310 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002311 }
2312
Johan Hedberg4ae143012013-01-20 14:27:13 +02002313 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2315 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002316
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002317 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002318 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002319
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002320 for (i = 0; i < key_count; i++) {
2321 struct mgmt_link_key_info *key = &cp->keys[i];
2322
Marcel Holtmann8e991132014-01-10 02:07:25 -08002323 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002324 return mgmt_cmd_status(sk, hdev->id,
2325 MGMT_OP_LOAD_LINK_KEYS,
2326 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002327 }
2328
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002329 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002330
2331 hci_link_keys_clear(hdev);
2332
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002334 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002335 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002336 changed = hci_dev_test_and_clear_flag(hdev,
2337 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002338
2339 if (changed)
2340 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002342 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002343 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344
Johan Hedberg58e92932014-06-24 14:00:26 +03002345 /* Always ignore debug keys and require a new pairing if
2346 * the user wants to use them.
2347 */
2348 if (key->type == HCI_LK_DEBUG_COMBINATION)
2349 continue;
2350
Johan Hedberg7652ff62014-06-24 13:15:49 +03002351 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2352 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353 }
2354
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002355 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002357 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002359 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360}
2361
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002362static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002364{
2365 struct mgmt_ev_device_unpaired ev;
2366
2367 bacpy(&ev.addr.bdaddr, bdaddr);
2368 ev.addr.type = addr_type;
2369
2370 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002372}
2373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002377 struct mgmt_cp_unpair_device *cp = data;
2378 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002379 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002380 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002381 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002382 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002383 int err;
2384
Johan Hedberga8a1d192011-11-10 15:54:38 +02002385 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002386 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2387 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002388
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002389 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002390 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2391 MGMT_STATUS_INVALID_PARAMS,
2392 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002393
Johan Hedberg118da702013-01-20 14:27:20 +02002394 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002395 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2396 MGMT_STATUS_INVALID_PARAMS,
2397 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002398
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399 hci_dev_lock(hdev);
2400
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002401 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002402 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2403 MGMT_STATUS_NOT_POWERED, &rp,
2404 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002405 goto unlock;
2406 }
2407
Johan Hedberge0b2b272014-02-18 17:14:31 +02002408 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002409 /* If disconnection is requested, then look up the
2410 * connection. If the remote device is connected, it
2411 * will be later used to terminate the link.
2412 *
2413 * Setting it to NULL explicitly will cause no
2414 * termination of the link.
2415 */
2416 if (cp->disconnect)
2417 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2418 &cp->addr.bdaddr);
2419 else
2420 conn = NULL;
2421
Johan Hedberg124f6e32012-02-09 13:50:12 +02002422 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002423 if (err < 0) {
2424 err = mgmt_cmd_complete(sk, hdev->id,
2425 MGMT_OP_UNPAIR_DEVICE,
2426 MGMT_STATUS_NOT_PAIRED, &rp,
2427 sizeof(rp));
2428 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002429 }
2430
Johan Hedbergec182f02015-10-21 18:03:03 +03002431 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002432 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002433
Johan Hedbergec182f02015-10-21 18:03:03 +03002434 /* LE address type */
2435 addr_type = le_addr_type(cp->addr.type);
2436
2437 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2438
2439 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002440 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002441 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2442 MGMT_STATUS_NOT_PAIRED, &rp,
2443 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002444 goto unlock;
2445 }
2446
Johan Hedbergec182f02015-10-21 18:03:03 +03002447 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2448 if (!conn) {
2449 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2450 goto done;
2451 }
2452
Johan Hedbergc81d5552015-10-22 09:38:35 +03002453 /* Abort any ongoing SMP pairing */
2454 smp_cancel_pairing(conn);
2455
Johan Hedbergec182f02015-10-21 18:03:03 +03002456 /* Defer clearing up the connection parameters until closing to
2457 * give a chance of keeping them if a repairing happens.
2458 */
2459 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2460
Johan Hedbergfc643612015-10-22 09:38:31 +03002461 /* Disable auto-connection parameters if present */
2462 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2463 if (params) {
2464 if (params->explicit_connect)
2465 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2466 else
2467 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2468 }
2469
Johan Hedbergec182f02015-10-21 18:03:03 +03002470 /* If disconnection is not requested, then clear the connection
2471 * variable so that the link is not terminated.
2472 */
2473 if (!cp->disconnect)
2474 conn = NULL;
2475
2476done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002477 /* If the connection variable is set, then termination of the
2478 * link is requested.
2479 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002480 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002481 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2482 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002483 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002484 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002485 }
2486
Johan Hedberg124f6e32012-02-09 13:50:12 +02002487 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002488 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002489 if (!cmd) {
2490 err = -ENOMEM;
2491 goto unlock;
2492 }
2493
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002494 cmd->cmd_complete = addr_cmd_complete;
2495
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002496 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002497 if (err < 0)
2498 mgmt_pending_remove(cmd);
2499
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002500unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002502 return err;
2503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002508 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002509 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002510 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002511 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002512 int err;
2513
2514 BT_DBG("");
2515
Johan Hedberg06a63b12013-01-20 14:27:21 +02002516 memset(&rp, 0, sizeof(rp));
2517 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2518 rp.addr.type = cp->addr.type;
2519
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002520 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002521 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2522 MGMT_STATUS_INVALID_PARAMS,
2523 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002526
2527 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002528 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2529 MGMT_STATUS_NOT_POWERED, &rp,
2530 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002531 goto failed;
2532 }
2533
Johan Hedberg333ae952015-03-17 13:48:47 +02002534 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002535 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2536 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002537 goto failed;
2538 }
2539
Andre Guedes591f47f2012-04-24 21:02:49 -03002540 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002541 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2542 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002543 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002544 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2545 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002546
Vishal Agarwalf9607272012-06-13 05:32:43 +05302547 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002548 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2549 MGMT_STATUS_NOT_CONNECTED, &rp,
2550 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002551 goto failed;
2552 }
2553
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002554 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002555 if (!cmd) {
2556 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002557 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002558 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002559
Johan Hedbergf5818c22014-12-05 13:36:02 +02002560 cmd->cmd_complete = generic_cmd_complete;
2561
Johan Hedberge3f2f922014-08-18 20:33:33 +03002562 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002563 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002564 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565
2566failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002567 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002568 return err;
2569}
2570
Andre Guedes57c14772012-04-24 21:02:50 -03002571static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002572{
2573 switch (link_type) {
2574 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002575 switch (addr_type) {
2576 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002577 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002578
Johan Hedberg48264f02011-11-09 13:58:58 +02002579 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002580 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002581 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002582 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002583
Johan Hedberg4c659c32011-11-07 23:13:39 +02002584 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002585 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002586 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002587 }
2588}
2589
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2591 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002592{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002593 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002594 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002595 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002596 int err;
2597 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002598
2599 BT_DBG("");
2600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002602
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002603 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002604 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2605 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002606 goto unlock;
2607 }
2608
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002609 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002610 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2611 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002612 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002613 }
2614
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002615 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002616 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002617 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002618 err = -ENOMEM;
2619 goto unlock;
2620 }
2621
Johan Hedberg2784eb42011-01-21 13:56:35 +02002622 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002623 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002624 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2625 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002626 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002627 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002628 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002629 continue;
2630 i++;
2631 }
2632
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002633 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002634
Johan Hedberg4c659c32011-11-07 23:13:39 +02002635 /* Recalculate length in case of filtered SCO connections, etc */
2636 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002637
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002638 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2639 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002640
Johan Hedberga38528f2011-01-22 06:46:43 +02002641 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002642
2643unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002644 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002645 return err;
2646}
2647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002650{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002651 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002652 int err;
2653
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002654 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002655 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002656 if (!cmd)
2657 return -ENOMEM;
2658
Arek Lichwadd7e39b2016-09-22 14:08:05 +02002659 cmd->cmd_complete = addr_cmd_complete;
2660
Johan Hedbergd8457692012-02-17 14:24:57 +02002661 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002662 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002663 if (err < 0)
2664 mgmt_pending_remove(cmd);
2665
2666 return err;
2667}
2668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002669static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002670 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002671{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002672 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002673 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002674 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002675 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002676 int err;
2677
2678 BT_DBG("");
2679
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002680 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002681
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002682 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002683 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2684 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002685 goto failed;
2686 }
2687
Johan Hedbergd8457692012-02-17 14:24:57 +02002688 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002689 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002690 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2691 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002692 goto failed;
2693 }
2694
2695 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002696 struct mgmt_cp_pin_code_neg_reply ncp;
2697
2698 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002699
Marcel Holtmann2064ee32017-10-30 10:42:59 +01002700 bt_dev_err(hdev, "PIN code is not 16 bytes long");
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002702 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002703 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002704 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2705 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002706
2707 goto failed;
2708 }
2709
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002710 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002711 if (!cmd) {
2712 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002713 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002714 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002716 cmd->cmd_complete = addr_cmd_complete;
2717
Johan Hedbergd8457692012-02-17 14:24:57 +02002718 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002719 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002720 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002721
2722 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2723 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002724 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725
2726failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002727 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 return err;
2729}
2730
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002731static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2732 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002733{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002734 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002735
2736 BT_DBG("");
2737
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002738 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002739 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2740 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002741
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002742 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002743
2744 hdev->io_capability = cp->io_capability;
2745
2746 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002747 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002748
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002749 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002750
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002751 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2752 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002753}
2754
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002755static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002756{
2757 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002758 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002759
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002760 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002761 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2762 continue;
2763
Johan Hedberge9a416b2011-02-19 12:05:56 -03002764 if (cmd->user_data != conn)
2765 continue;
2766
2767 return cmd;
2768 }
2769
2770 return NULL;
2771}
2772
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002773static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002774{
2775 struct mgmt_rp_pair_device rp;
2776 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002777 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002778
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002779 bacpy(&rp.addr.bdaddr, &conn->dst);
2780 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002781
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002782 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2783 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002784
2785 /* So we don't get further callbacks for this connection */
2786 conn->connect_cfm_cb = NULL;
2787 conn->security_cfm_cb = NULL;
2788 conn->disconn_cfm_cb = NULL;
2789
David Herrmann76a68ba2013-04-06 20:28:37 +02002790 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002791
2792 /* The device is paired so there is no need to remove
2793 * its connection parameters anymore.
2794 */
2795 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002796
2797 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002798
2799 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002800}
2801
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002802void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2803{
2804 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002805 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002806
2807 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002808 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002809 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002810 mgmt_pending_remove(cmd);
2811 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002812}
2813
Johan Hedberge9a416b2011-02-19 12:05:56 -03002814static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2815{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002816 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002817
2818 BT_DBG("status %u", status);
2819
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002820 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002821 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002822 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002823 return;
2824 }
2825
2826 cmd->cmd_complete(cmd, mgmt_status(status));
2827 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002828}
2829
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002830static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302831{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002832 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302833
2834 BT_DBG("status %u", status);
2835
2836 if (!status)
2837 return;
2838
2839 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002840 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302841 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002842 return;
2843 }
2844
2845 cmd->cmd_complete(cmd, mgmt_status(status));
2846 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302847}
2848
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002849static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002850 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002851{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002852 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002853 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002854 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002855 u8 sec_level, auth_type;
2856 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002857 int err;
2858
2859 BT_DBG("");
2860
Szymon Jancf950a30e2013-01-18 12:48:07 +01002861 memset(&rp, 0, sizeof(rp));
2862 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2863 rp.addr.type = cp->addr.type;
2864
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002865 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002866 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2867 MGMT_STATUS_INVALID_PARAMS,
2868 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002869
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002870 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002871 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2872 MGMT_STATUS_INVALID_PARAMS,
2873 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002874
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002875 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002876
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002877 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002878 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2879 MGMT_STATUS_NOT_POWERED, &rp,
2880 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002881 goto unlock;
2882 }
2883
Johan Hedberg55e76b32015-03-10 22:34:40 +02002884 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2885 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2886 MGMT_STATUS_ALREADY_PAIRED, &rp,
2887 sizeof(rp));
2888 goto unlock;
2889 }
2890
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002891 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002892 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002893
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002894 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002895 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2896 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002897 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002898 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002899 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002900
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002901 /* When pairing a new device, it is expected to remember
2902 * this device for future connections. Adding the connection
2903 * parameter information ahead of time allows tracking
2904 * of the slave preferred values and will speed up any
2905 * further connection establishment.
2906 *
2907 * If connection parameters already exist, then they
2908 * will be kept and this function does nothing.
2909 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002910 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2911
2912 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2913 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002914
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002915 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2916 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002917 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002918 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002919
Ville Tervo30e76272011-02-22 16:10:53 -03002920 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002921 int status;
2922
2923 if (PTR_ERR(conn) == -EBUSY)
2924 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002925 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2926 status = MGMT_STATUS_NOT_SUPPORTED;
2927 else if (PTR_ERR(conn) == -ECONNREFUSED)
2928 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002929 else
2930 status = MGMT_STATUS_CONNECT_FAILED;
2931
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002932 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2933 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002934 goto unlock;
2935 }
2936
2937 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002938 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002939 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2940 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002941 goto unlock;
2942 }
2943
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002944 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002945 if (!cmd) {
2946 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002947 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002948 goto unlock;
2949 }
2950
Johan Hedberg04ab2742014-12-05 13:36:04 +02002951 cmd->cmd_complete = pairing_complete;
2952
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002953 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002954 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002955 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002956 conn->security_cfm_cb = pairing_complete_cb;
2957 conn->disconn_cfm_cb = pairing_complete_cb;
2958 } else {
2959 conn->connect_cfm_cb = le_pairing_complete_cb;
2960 conn->security_cfm_cb = le_pairing_complete_cb;
2961 conn->disconn_cfm_cb = le_pairing_complete_cb;
2962 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002963
Johan Hedberge9a416b2011-02-19 12:05:56 -03002964 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002965 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002966
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002967 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002968 hci_conn_security(conn, sec_level, auth_type, true)) {
2969 cmd->cmd_complete(cmd, 0);
2970 mgmt_pending_remove(cmd);
2971 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002972
2973 err = 0;
2974
2975unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002976 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002977 return err;
2978}
2979
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002980static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2981 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002982{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002983 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002984 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002985 struct hci_conn *conn;
2986 int err;
2987
2988 BT_DBG("");
2989
Johan Hedberg28424702012-02-02 04:02:29 +02002990 hci_dev_lock(hdev);
2991
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002992 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002993 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2994 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002995 goto unlock;
2996 }
2997
Johan Hedberg333ae952015-03-17 13:48:47 +02002998 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002999 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003000 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3001 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003002 goto unlock;
3003 }
3004
3005 conn = cmd->user_data;
3006
3007 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003008 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3009 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003010 goto unlock;
3011 }
3012
Johan Hedberga511b352014-12-11 21:45:45 +02003013 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3014 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003015
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003016 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3017 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003018unlock:
3019 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003020 return err;
3021}
3022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003023static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003024 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003025 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003026{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003027 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003028 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003029 int err;
3030
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003031 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003032
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003033 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003034 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3035 MGMT_STATUS_NOT_POWERED, addr,
3036 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003037 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003038 }
3039
Johan Hedberg1707c602013-03-15 17:07:15 -05003040 if (addr->type == BDADDR_BREDR)
3041 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003042 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003043 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3044 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003045
Johan Hedberg272d90d2012-02-09 15:26:12 +02003046 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003047 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3048 MGMT_STATUS_NOT_CONNECTED, addr,
3049 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003050 goto done;
3051 }
3052
Johan Hedberg1707c602013-03-15 17:07:15 -05003053 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003054 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003055 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003056 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3057 MGMT_STATUS_SUCCESS, addr,
3058 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003059 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003060 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3061 MGMT_STATUS_FAILED, addr,
3062 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003063
Brian Gix47c15e22011-11-16 13:53:14 -08003064 goto done;
3065 }
3066
Johan Hedberg1707c602013-03-15 17:07:15 -05003067 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003068 if (!cmd) {
3069 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003070 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003071 }
3072
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003073 cmd->cmd_complete = addr_cmd_complete;
3074
Brian Gix0df4c182011-11-16 13:53:13 -08003075 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003076 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3077 struct hci_cp_user_passkey_reply cp;
3078
Johan Hedberg1707c602013-03-15 17:07:15 -05003079 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003080 cp.passkey = passkey;
3081 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3082 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003083 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3084 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003085
Johan Hedberga664b5b2011-02-19 12:06:02 -03003086 if (err < 0)
3087 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003088
Brian Gix0df4c182011-11-16 13:53:13 -08003089done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003090 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003091 return err;
3092}
3093
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303094static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3095 void *data, u16 len)
3096{
3097 struct mgmt_cp_pin_code_neg_reply *cp = data;
3098
3099 BT_DBG("");
3100
Johan Hedberg1707c602013-03-15 17:07:15 -05003101 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303102 MGMT_OP_PIN_CODE_NEG_REPLY,
3103 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3104}
3105
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003106static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3107 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003108{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003109 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003110
3111 BT_DBG("");
3112
3113 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003114 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3115 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003116
Johan Hedberg1707c602013-03-15 17:07:15 -05003117 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003118 MGMT_OP_USER_CONFIRM_REPLY,
3119 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003120}
3121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003122static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003124{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003125 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003126
3127 BT_DBG("");
3128
Johan Hedberg1707c602013-03-15 17:07:15 -05003129 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003130 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3131 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003132}
3133
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003134static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3135 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003136{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003137 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003138
3139 BT_DBG("");
3140
Johan Hedberg1707c602013-03-15 17:07:15 -05003141 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003142 MGMT_OP_USER_PASSKEY_REPLY,
3143 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003144}
3145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003146static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003147 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003149 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003150
3151 BT_DBG("");
3152
Johan Hedberg1707c602013-03-15 17:07:15 -05003153 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003154 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3155 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003156}
3157
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003158static void adv_expire(struct hci_dev *hdev, u32 flags)
3159{
3160 struct adv_info *adv_instance;
3161 struct hci_request req;
3162 int err;
3163
3164 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3165 if (!adv_instance)
3166 return;
3167
3168 /* stop if current instance doesn't need to be changed */
3169 if (!(adv_instance->flags & flags))
3170 return;
3171
3172 cancel_adv_timeout(hdev);
3173
3174 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3175 if (!adv_instance)
3176 return;
3177
3178 hci_req_init(&req, hdev);
3179 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3180 true);
3181 if (err)
3182 return;
3183
3184 hci_req_run(&req, NULL);
3185}
3186
Marcel Holtmann1904a852015-01-11 13:50:44 -08003187static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003188{
3189 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003190 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003191
3192 BT_DBG("status 0x%02x", status);
3193
3194 hci_dev_lock(hdev);
3195
Johan Hedberg333ae952015-03-17 13:48:47 +02003196 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003197 if (!cmd)
3198 goto unlock;
3199
3200 cp = cmd->param;
3201
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003202 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003203 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3204 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003205 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003206 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3207 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003208
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003209 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3210 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3211 }
3212
Johan Hedberg13928972013-03-15 17:07:00 -05003213 mgmt_pending_remove(cmd);
3214
3215unlock:
3216 hci_dev_unlock(hdev);
3217}
3218
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003219static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003220 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003221{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003222 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003223 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003224 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003225 int err;
3226
3227 BT_DBG("");
3228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003229 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003230
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003231 /* If the old values are the same as the new ones just return a
3232 * direct command complete event.
3233 */
3234 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3235 !memcmp(hdev->short_name, cp->short_name,
3236 sizeof(hdev->short_name))) {
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 Hedbergb3f2ca92013-03-15 17:07:03 -05003239 goto failed;
3240 }
3241
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003242 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003243
Johan Hedbergb5235a62012-02-21 14:32:24 +02003244 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003245 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003246
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003247 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3248 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003249 if (err < 0)
3250 goto failed;
3251
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003252 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3253 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003254 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003255
Johan Hedbergb5235a62012-02-21 14:32:24 +02003256 goto failed;
3257 }
3258
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003259 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003260 if (!cmd) {
3261 err = -ENOMEM;
3262 goto failed;
3263 }
3264
Johan Hedberg13928972013-03-15 17:07:00 -05003265 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3266
Johan Hedberg890ea892013-03-15 17:06:52 -05003267 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003268
3269 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003270 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003271 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003272 }
3273
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003274 /* The name is stored in the scan response data and so
3275 * no need to udpate the advertising data here.
3276 */
MichaƂ Narajowski7dc6f162016-09-22 16:01:39 +02003277 if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003278 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003279
Johan Hedberg13928972013-03-15 17:07:00 -05003280 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003281 if (err < 0)
3282 mgmt_pending_remove(cmd);
3283
3284failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003285 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003286 return err;
3287}
3288
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003289static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3290 u16 len)
3291{
3292 struct mgmt_cp_set_appearance *cp = data;
3293 u16 apperance;
3294 int err;
3295
3296 BT_DBG("");
3297
MichaƂ Narajowskiaf4168c2016-09-19 14:33:33 +02003298 if (!lmp_le_capable(hdev))
3299 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
3300 MGMT_STATUS_NOT_SUPPORTED);
3301
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003302 apperance = le16_to_cpu(cp->appearance);
3303
3304 hci_dev_lock(hdev);
3305
3306 if (hdev->appearance != apperance) {
3307 hdev->appearance = apperance;
3308
3309 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3310 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
MichaƂ Narajowskie74317f2016-09-19 20:25:56 +02003311
3312 ext_info_changed(hdev, sk);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003313 }
3314
3315 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3316 0);
3317
3318 hci_dev_unlock(hdev);
3319
3320 return err;
3321}
3322
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05303323static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3324 void *data, u16 len)
3325{
3326 struct mgmt_rp_get_phy_confguration rp;
3327
3328 BT_DBG("sock %p %s", sk, hdev->name);
3329
3330 hci_dev_lock(hdev);
3331
3332 memset(&rp, 0, sizeof(rp));
3333
3334 rp.supported_phys = cpu_to_le32(get_supported_phys(hdev));
3335 rp.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3336 rp.configurable_phys = cpu_to_le32(get_configurable_phys(hdev));
3337
3338 hci_dev_unlock(hdev);
3339
3340 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_PHY_CONFIGURATION, 0,
3341 &rp, sizeof(rp));
3342}
3343
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303344int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
3345{
3346 struct mgmt_ev_phy_configuration_changed ev;
3347
3348 memset(&ev, 0, sizeof(ev));
3349
3350 ev.selected_phys = cpu_to_le32(get_selected_phys(hdev));
3351
3352 return mgmt_event(MGMT_EV_PHY_CONFIGURATION_CHANGED, hdev, &ev,
3353 sizeof(ev), skip);
3354}
3355
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303356static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3357 u16 opcode, struct sk_buff *skb)
3358{
3359 struct mgmt_cp_set_phy_confguration *cp;
3360 struct mgmt_pending_cmd *cmd;
3361
3362 BT_DBG("status 0x%02x", status);
3363
3364 hci_dev_lock(hdev);
3365
3366 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3367 if (!cmd)
3368 goto unlock;
3369
3370 cp = cmd->param;
3371
3372 if (status) {
3373 mgmt_cmd_status(cmd->sk, hdev->id,
3374 MGMT_OP_SET_PHY_CONFIGURATION,
3375 mgmt_status(status));
3376 } else {
3377 mgmt_cmd_complete(cmd->sk, hdev->id,
3378 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3379 NULL, 0);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303380
3381 mgmt_phy_configuration_changed(hdev, cmd->sk);
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303382 }
3383
3384 mgmt_pending_remove(cmd);
3385
3386unlock:
3387 hci_dev_unlock(hdev);
3388}
3389
3390static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3391 void *data, u16 len)
3392{
3393 struct mgmt_cp_set_phy_confguration *cp = data;
3394 struct hci_cp_le_set_default_phy cp_phy;
3395 struct mgmt_pending_cmd *cmd;
3396 struct hci_request req;
3397 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3398 u16 pkt_type = (HCI_DH1 | HCI_DM1);
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303399 bool changed = false;
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303400 int err;
3401
3402 BT_DBG("sock %p %s", sk, hdev->name);
3403
3404 configurable_phys = get_configurable_phys(hdev);
3405 supported_phys = get_supported_phys(hdev);
3406 selected_phys = __le32_to_cpu(cp->selected_phys);
3407
3408 if (selected_phys & ~supported_phys)
3409 return mgmt_cmd_status(sk, hdev->id,
3410 MGMT_OP_SET_PHY_CONFIGURATION,
3411 MGMT_STATUS_INVALID_PARAMS);
3412
3413 unconfigure_phys = supported_phys & ~configurable_phys;
3414
3415 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3416 return mgmt_cmd_status(sk, hdev->id,
3417 MGMT_OP_SET_PHY_CONFIGURATION,
3418 MGMT_STATUS_INVALID_PARAMS);
3419
3420 if (selected_phys == get_selected_phys(hdev))
3421 return mgmt_cmd_complete(sk, hdev->id,
3422 MGMT_OP_SET_PHY_CONFIGURATION,
3423 0, NULL, 0);
3424
3425 hci_dev_lock(hdev);
3426
3427 if (!hdev_is_powered(hdev)) {
3428 err = mgmt_cmd_status(sk, hdev->id,
3429 MGMT_OP_SET_PHY_CONFIGURATION,
3430 MGMT_STATUS_REJECTED);
3431 goto unlock;
3432 }
3433
3434 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3435 err = mgmt_cmd_status(sk, hdev->id,
3436 MGMT_OP_SET_PHY_CONFIGURATION,
3437 MGMT_STATUS_BUSY);
3438 goto unlock;
3439 }
3440
3441 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3442 pkt_type |= (HCI_DH3 | HCI_DM3);
3443 else
3444 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3445
3446 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3447 pkt_type |= (HCI_DH5 | HCI_DM5);
3448 else
3449 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3450
3451 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3452 pkt_type &= ~HCI_2DH1;
3453 else
3454 pkt_type |= HCI_2DH1;
3455
3456 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3457 pkt_type &= ~HCI_2DH3;
3458 else
3459 pkt_type |= HCI_2DH3;
3460
3461 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3462 pkt_type &= ~HCI_2DH5;
3463 else
3464 pkt_type |= HCI_2DH5;
3465
3466 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3467 pkt_type &= ~HCI_3DH1;
3468 else
3469 pkt_type |= HCI_3DH1;
3470
3471 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3472 pkt_type &= ~HCI_3DH3;
3473 else
3474 pkt_type |= HCI_3DH3;
3475
3476 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3477 pkt_type &= ~HCI_3DH5;
3478 else
3479 pkt_type |= HCI_3DH5;
3480
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303481 if (pkt_type != hdev->pkt_type) {
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303482 hdev->pkt_type = pkt_type;
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303483 changed = true;
3484 }
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303485
3486 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3487 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
Jaganath Kanakkasseryb7c23df2018-07-19 17:09:36 +05303488 if (changed)
3489 mgmt_phy_configuration_changed(hdev, sk);
3490
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05303491 err = mgmt_cmd_complete(sk, hdev->id,
3492 MGMT_OP_SET_PHY_CONFIGURATION,
3493 0, NULL, 0);
3494
3495 goto unlock;
3496 }
3497
3498 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3499 len);
3500 if (!cmd) {
3501 err = -ENOMEM;
3502 goto unlock;
3503 }
3504
3505 hci_req_init(&req, hdev);
3506
3507 memset(&cp_phy, 0, sizeof(cp_phy));
3508
3509 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3510 cp_phy.all_phys |= 0x01;
3511
3512 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3513 cp_phy.all_phys |= 0x02;
3514
3515 if (selected_phys & MGMT_PHY_LE_1M_TX)
3516 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3517
3518 if (selected_phys & MGMT_PHY_LE_2M_TX)
3519 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3520
3521 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3522 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3523
3524 if (selected_phys & MGMT_PHY_LE_1M_RX)
3525 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3526
3527 if (selected_phys & MGMT_PHY_LE_2M_RX)
3528 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3529
3530 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3531 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3532
3533 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3534
3535 err = hci_req_run_skb(&req, set_default_phy_complete);
3536 if (err < 0)
3537 mgmt_pending_remove(cmd);
3538
3539unlock:
3540 hci_dev_unlock(hdev);
3541
3542 return err;
3543}
3544
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003545static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3546 u16 opcode, struct sk_buff *skb)
3547{
3548 struct mgmt_rp_read_local_oob_data mgmt_rp;
3549 size_t rp_size = sizeof(mgmt_rp);
3550 struct mgmt_pending_cmd *cmd;
3551
3552 BT_DBG("%s status %u", hdev->name, status);
3553
3554 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3555 if (!cmd)
3556 return;
3557
3558 if (status || !skb) {
3559 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3560 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3561 goto remove;
3562 }
3563
3564 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3565
3566 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3567 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3568
3569 if (skb->len < sizeof(*rp)) {
3570 mgmt_cmd_status(cmd->sk, hdev->id,
3571 MGMT_OP_READ_LOCAL_OOB_DATA,
3572 MGMT_STATUS_FAILED);
3573 goto remove;
3574 }
3575
3576 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3577 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3578
3579 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3580 } else {
3581 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3582
3583 if (skb->len < sizeof(*rp)) {
3584 mgmt_cmd_status(cmd->sk, hdev->id,
3585 MGMT_OP_READ_LOCAL_OOB_DATA,
3586 MGMT_STATUS_FAILED);
3587 goto remove;
3588 }
3589
3590 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3591 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3592
3593 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3594 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3595 }
3596
3597 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3598 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3599
3600remove:
3601 mgmt_pending_remove(cmd);
3602}
3603
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003604static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003605 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003606{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003607 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003608 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003609 int err;
3610
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003611 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003613 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003614
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003615 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003616 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3617 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003618 goto unlock;
3619 }
3620
Andre Guedes9a1a1992012-07-24 15:03:48 -03003621 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003622 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3623 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003624 goto unlock;
3625 }
3626
Johan Hedberg333ae952015-03-17 13:48:47 +02003627 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003628 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3629 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003630 goto unlock;
3631 }
3632
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003633 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003634 if (!cmd) {
3635 err = -ENOMEM;
3636 goto unlock;
3637 }
3638
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003639 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003640
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003641 if (bredr_sc_enabled(hdev))
3642 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3643 else
3644 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3645
3646 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003647 if (err < 0)
3648 mgmt_pending_remove(cmd);
3649
3650unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003651 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003652 return err;
3653}
3654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003655static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003656 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003657{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003658 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003659 int err;
3660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003661 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003662
Johan Hedberg5d57e792015-01-23 10:10:38 +02003663 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003664 return mgmt_cmd_complete(sk, hdev->id,
3665 MGMT_OP_ADD_REMOTE_OOB_DATA,
3666 MGMT_STATUS_INVALID_PARAMS,
3667 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003668
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003669 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003670
Marcel Holtmannec109112014-01-10 02:07:30 -08003671 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3672 struct mgmt_cp_add_remote_oob_data *cp = data;
3673 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003674
Johan Hedbergc19a4952014-11-17 20:52:19 +02003675 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003676 err = mgmt_cmd_complete(sk, hdev->id,
3677 MGMT_OP_ADD_REMOTE_OOB_DATA,
3678 MGMT_STATUS_INVALID_PARAMS,
3679 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003680 goto unlock;
3681 }
3682
Marcel Holtmannec109112014-01-10 02:07:30 -08003683 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003684 cp->addr.type, cp->hash,
3685 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003686 if (err < 0)
3687 status = MGMT_STATUS_FAILED;
3688 else
3689 status = MGMT_STATUS_SUCCESS;
3690
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003691 err = mgmt_cmd_complete(sk, hdev->id,
3692 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3693 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003694 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3695 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003696 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003697 u8 status;
3698
Johan Hedberg86df9202014-10-26 20:52:27 +01003699 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003700 /* Enforce zero-valued 192-bit parameters as
3701 * long as legacy SMP OOB isn't implemented.
3702 */
3703 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3704 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003705 err = mgmt_cmd_complete(sk, hdev->id,
3706 MGMT_OP_ADD_REMOTE_OOB_DATA,
3707 MGMT_STATUS_INVALID_PARAMS,
3708 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003709 goto unlock;
3710 }
3711
Johan Hedberg86df9202014-10-26 20:52:27 +01003712 rand192 = NULL;
3713 hash192 = NULL;
3714 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003715 /* In case one of the P-192 values is set to zero,
3716 * then just disable OOB data for P-192.
3717 */
3718 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3719 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3720 rand192 = NULL;
3721 hash192 = NULL;
3722 } else {
3723 rand192 = cp->rand192;
3724 hash192 = cp->hash192;
3725 }
3726 }
3727
3728 /* In case one of the P-256 values is set to zero, then just
3729 * disable OOB data for P-256.
3730 */
3731 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3732 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3733 rand256 = NULL;
3734 hash256 = NULL;
3735 } else {
3736 rand256 = cp->rand256;
3737 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003738 }
3739
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003740 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003741 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003742 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003743 if (err < 0)
3744 status = MGMT_STATUS_FAILED;
3745 else
3746 status = MGMT_STATUS_SUCCESS;
3747
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003748 err = mgmt_cmd_complete(sk, hdev->id,
3749 MGMT_OP_ADD_REMOTE_OOB_DATA,
3750 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003751 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003752 bt_dev_err(hdev, "add_remote_oob_data: invalid len of %u bytes",
3753 len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003754 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3755 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003756 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003757
Johan Hedbergc19a4952014-11-17 20:52:19 +02003758unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003759 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003760 return err;
3761}
3762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003763static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003764 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003765{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003766 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003767 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003768 int err;
3769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003770 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003771
Johan Hedbergc19a4952014-11-17 20:52:19 +02003772 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003773 return mgmt_cmd_complete(sk, hdev->id,
3774 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3775 MGMT_STATUS_INVALID_PARAMS,
3776 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003777
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003778 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003779
Johan Hedbergeedbd582014-11-15 09:34:23 +02003780 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3781 hci_remote_oob_data_clear(hdev);
3782 status = MGMT_STATUS_SUCCESS;
3783 goto done;
3784 }
3785
Johan Hedberg6928a922014-10-26 20:46:09 +01003786 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003787 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003788 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003789 else
Szymon Janca6785be2012-12-13 15:11:21 +01003790 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003791
Johan Hedbergeedbd582014-11-15 09:34:23 +02003792done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003793 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3794 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003795
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003796 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003797 return err;
3798}
3799
Johan Hedberge68f0722015-11-11 08:30:30 +02003800void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003801{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003802 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003803
Andre Guedes7c307722013-04-30 15:29:28 -03003804 BT_DBG("status %d", status);
3805
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003806 hci_dev_lock(hdev);
3807
Johan Hedberg333ae952015-03-17 13:48:47 +02003808 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003809 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003810 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003811
Johan Hedberg78b781c2016-01-05 13:19:32 +02003812 if (!cmd)
3813 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3814
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003815 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003816 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003817 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003818 }
3819
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003820 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003821}
3822
Johan Hedberg591752a2015-11-11 08:11:24 +02003823static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3824 uint8_t *mgmt_status)
3825{
3826 switch (type) {
3827 case DISCOV_TYPE_LE:
3828 *mgmt_status = mgmt_le_support(hdev);
3829 if (*mgmt_status)
3830 return false;
3831 break;
3832 case DISCOV_TYPE_INTERLEAVED:
3833 *mgmt_status = mgmt_le_support(hdev);
3834 if (*mgmt_status)
3835 return false;
3836 /* Intentional fall-through */
3837 case DISCOV_TYPE_BREDR:
3838 *mgmt_status = mgmt_bredr_support(hdev);
3839 if (*mgmt_status)
3840 return false;
3841 break;
3842 default:
3843 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3844 return false;
3845 }
3846
3847 return true;
3848}
3849
Johan Hedberg78b781c2016-01-05 13:19:32 +02003850static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3851 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003852{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003853 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003854 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003855 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003856 int err;
3857
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003858 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003859
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003860 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003861
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003862 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003863 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003864 MGMT_STATUS_NOT_POWERED,
3865 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003866 goto failed;
3867 }
3868
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003869 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003870 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003871 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3872 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003873 goto failed;
3874 }
3875
Johan Hedberg591752a2015-11-11 08:11:24 +02003876 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003877 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3878 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003879 goto failed;
3880 }
3881
Marcel Holtmann22078802014-12-05 11:45:22 +01003882 /* Clear the discovery filter first to free any previously
3883 * allocated memory for the UUID list.
3884 */
3885 hci_discovery_filter_clear(hdev);
3886
Andre Guedes4aab14e2012-02-17 20:39:36 -03003887 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003888 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003889 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3890 hdev->discovery.limited = true;
3891 else
3892 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003893
Johan Hedberg78b781c2016-01-05 13:19:32 +02003894 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003895 if (!cmd) {
3896 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003897 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003898 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003899
Johan Hedberge68f0722015-11-11 08:30:30 +02003900 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003901
3902 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003903 queue_work(hdev->req_workqueue, &hdev->discov_update);
3904 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003905
3906failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003907 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003908 return err;
3909}
3910
Johan Hedberg78b781c2016-01-05 13:19:32 +02003911static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3912 void *data, u16 len)
3913{
3914 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3915 data, len);
3916}
3917
3918static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3919 void *data, u16 len)
3920{
3921 return start_discovery_internal(sk, hdev,
3922 MGMT_OP_START_LIMITED_DISCOVERY,
3923 data, len);
3924}
3925
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003926static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3927 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003928{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003929 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3930 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003931}
3932
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003933static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3934 void *data, u16 len)
3935{
3936 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003937 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003938 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3939 u16 uuid_count, expected_len;
3940 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003941 int err;
3942
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003943 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003944
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003945 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003946
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003947 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003948 err = mgmt_cmd_complete(sk, hdev->id,
3949 MGMT_OP_START_SERVICE_DISCOVERY,
3950 MGMT_STATUS_NOT_POWERED,
3951 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003952 goto failed;
3953 }
3954
3955 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003956 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003957 err = mgmt_cmd_complete(sk, hdev->id,
3958 MGMT_OP_START_SERVICE_DISCOVERY,
3959 MGMT_STATUS_BUSY, &cp->type,
3960 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003961 goto failed;
3962 }
3963
3964 uuid_count = __le16_to_cpu(cp->uuid_count);
3965 if (uuid_count > max_uuid_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003966 bt_dev_err(hdev, "service_discovery: too big uuid_count value %u",
3967 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003968 err = mgmt_cmd_complete(sk, hdev->id,
3969 MGMT_OP_START_SERVICE_DISCOVERY,
3970 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3971 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003972 goto failed;
3973 }
3974
3975 expected_len = sizeof(*cp) + uuid_count * 16;
3976 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01003977 bt_dev_err(hdev, "service_discovery: expected %u bytes, got %u bytes",
3978 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003979 err = mgmt_cmd_complete(sk, hdev->id,
3980 MGMT_OP_START_SERVICE_DISCOVERY,
3981 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3982 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003983 goto failed;
3984 }
3985
Johan Hedberg591752a2015-11-11 08:11:24 +02003986 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3987 err = mgmt_cmd_complete(sk, hdev->id,
3988 MGMT_OP_START_SERVICE_DISCOVERY,
3989 status, &cp->type, sizeof(cp->type));
3990 goto failed;
3991 }
3992
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003993 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003994 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003995 if (!cmd) {
3996 err = -ENOMEM;
3997 goto failed;
3998 }
3999
Johan Hedberg2922a942014-12-05 13:36:06 +02004000 cmd->cmd_complete = service_discovery_cmd_complete;
4001
Marcel Holtmann22078802014-12-05 11:45:22 +01004002 /* Clear the discovery filter first to free any previously
4003 * allocated memory for the UUID list.
4004 */
4005 hci_discovery_filter_clear(hdev);
4006
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004007 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004008 hdev->discovery.type = cp->type;
4009 hdev->discovery.rssi = cp->rssi;
4010 hdev->discovery.uuid_count = uuid_count;
4011
4012 if (uuid_count > 0) {
4013 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4014 GFP_KERNEL);
4015 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004016 err = mgmt_cmd_complete(sk, hdev->id,
4017 MGMT_OP_START_SERVICE_DISCOVERY,
4018 MGMT_STATUS_FAILED,
4019 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004020 mgmt_pending_remove(cmd);
4021 goto failed;
4022 }
4023 }
4024
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004025 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02004026 queue_work(hdev->req_workqueue, &hdev->discov_update);
4027 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004028
4029failed:
4030 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004031 return err;
4032}
4033
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004034void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004035{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004036 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004037
Andre Guedes0e05bba2013-04-30 15:29:33 -03004038 BT_DBG("status %d", status);
4039
4040 hci_dev_lock(hdev);
4041
Johan Hedberg333ae952015-03-17 13:48:47 +02004042 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004043 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004044 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004045 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004046 }
4047
Andre Guedes0e05bba2013-04-30 15:29:33 -03004048 hci_dev_unlock(hdev);
4049}
4050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004051static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004052 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004053{
Johan Hedbergd9306502012-02-20 23:25:18 +02004054 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004055 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04004056 int err;
4057
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004058 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004059
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004060 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004061
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004062 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004063 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4064 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4065 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004066 goto unlock;
4067 }
4068
4069 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004070 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4071 MGMT_STATUS_INVALID_PARAMS,
4072 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004073 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004074 }
4075
Johan Hedberg2922a942014-12-05 13:36:06 +02004076 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004077 if (!cmd) {
4078 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004079 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004080 }
4081
Johan Hedberg2922a942014-12-05 13:36:06 +02004082 cmd->cmd_complete = generic_cmd_complete;
4083
Johan Hedberg2154d3f2015-11-11 08:30:45 +02004084 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
4085 queue_work(hdev->req_workqueue, &hdev->discov_update);
4086 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04004087
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004088unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004089 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004090 return err;
4091}
4092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004093static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004094 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004095{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004096 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004097 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004098 int err;
4099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004100 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004101
Johan Hedberg561aafb2012-01-04 13:31:59 +02004102 hci_dev_lock(hdev);
4103
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004104 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004105 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4106 MGMT_STATUS_FAILED, &cp->addr,
4107 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004108 goto failed;
4109 }
4110
Johan Hedberga198e7b2012-02-17 14:27:06 +02004111 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004112 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004113 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4114 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4115 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004116 goto failed;
4117 }
4118
4119 if (cp->name_known) {
4120 e->name_state = NAME_KNOWN;
4121 list_del(&e->list);
4122 } else {
4123 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004124 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004125 }
4126
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004127 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4128 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004129
4130failed:
4131 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004132 return err;
4133}
4134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004135static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004136 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004137{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004138 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004139 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004140 int err;
4141
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004142 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004143
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004144 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004145 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4146 MGMT_STATUS_INVALID_PARAMS,
4147 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004148
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004149 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004150
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004151 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4152 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004153 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004154 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004155 goto done;
4156 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004157
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004158 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4159 sk);
4160 status = MGMT_STATUS_SUCCESS;
4161
4162done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004163 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4164 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004166 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004167
4168 return err;
4169}
4170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004171static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004173{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004174 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004175 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004176 int err;
4177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004178 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004179
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004180 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004181 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4182 MGMT_STATUS_INVALID_PARAMS,
4183 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004185 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004186
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004187 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4188 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004189 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004190 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004191 goto done;
4192 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004193
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004194 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4195 sk);
4196 status = MGMT_STATUS_SUCCESS;
4197
4198done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004199 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4200 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004201
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004202 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004203
4204 return err;
4205}
4206
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004207static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4208 u16 len)
4209{
4210 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004211 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004212 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004213 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004214
4215 BT_DBG("%s", hdev->name);
4216
Szymon Jancc72d4b82012-03-16 16:02:57 +01004217 source = __le16_to_cpu(cp->source);
4218
4219 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004220 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4221 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004222
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004223 hci_dev_lock(hdev);
4224
Szymon Jancc72d4b82012-03-16 16:02:57 +01004225 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004226 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4227 hdev->devid_product = __le16_to_cpu(cp->product);
4228 hdev->devid_version = __le16_to_cpu(cp->version);
4229
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004230 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4231 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004232
Johan Hedberg890ea892013-03-15 17:06:52 -05004233 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02004234 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004235 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004236
4237 hci_dev_unlock(hdev);
4238
4239 return err;
4240}
4241
Arman Uguray24b4f382015-03-23 15:57:12 -07004242static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4243 u16 opcode)
4244{
4245 BT_DBG("status %d", status);
4246}
4247
Marcel Holtmann1904a852015-01-11 13:50:44 -08004248static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4249 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004250{
4251 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004252 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004253 u8 instance;
4254 struct adv_info *adv_instance;
4255 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004256
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304257 hci_dev_lock(hdev);
4258
Johan Hedberg4375f102013-09-25 13:26:10 +03004259 if (status) {
4260 u8 mgmt_err = mgmt_status(status);
4261
4262 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4263 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304264 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004265 }
4266
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004267 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004268 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004269 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004270 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004271
Johan Hedberg4375f102013-09-25 13:26:10 +03004272 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4273 &match);
4274
4275 new_settings(hdev, match.sk);
4276
4277 if (match.sk)
4278 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304279
Arman Uguray24b4f382015-03-23 15:57:12 -07004280 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004281 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004282 */
4283 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004284 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004285 goto unlock;
4286
Florian Grandel7816b822015-06-18 03:16:45 +02004287 instance = hdev->cur_adv_instance;
4288 if (!instance) {
4289 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4290 struct adv_info, list);
4291 if (!adv_instance)
4292 goto unlock;
4293
4294 instance = adv_instance->instance;
4295 }
4296
Arman Uguray24b4f382015-03-23 15:57:12 -07004297 hci_req_init(&req, hdev);
4298
Johan Hedbergf2252572015-11-18 12:49:20 +02004299 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004300
Florian Grandel7816b822015-06-18 03:16:45 +02004301 if (!err)
4302 err = hci_req_run(&req, enable_advertising_instance);
4303
4304 if (err)
Marcel Holtmann2064ee32017-10-30 10:42:59 +01004305 bt_dev_err(hdev, "failed to re-configure advertising");
Arman Uguray24b4f382015-03-23 15:57:12 -07004306
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304307unlock:
4308 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004309}
4310
Marcel Holtmann21b51872013-10-10 09:47:53 -07004311static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4312 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004313{
4314 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004315 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004316 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004317 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004318 int err;
4319
4320 BT_DBG("request for %s", hdev->name);
4321
Johan Hedberge6fe7982013-10-02 15:45:22 +03004322 status = mgmt_le_support(hdev);
4323 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004324 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4325 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004326
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004327 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004328 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4329 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004330
4331 hci_dev_lock(hdev);
4332
4333 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004334
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004335 /* The following conditions are ones which mean that we should
4336 * not do any HCI communication but directly send a mgmt
4337 * response to user space (after toggling the flag if
4338 * necessary).
4339 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004340 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004341 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4342 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004343 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004344 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004345 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004346 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004347
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004348 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02004349 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07004350 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004351 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004352 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004353 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004354 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004355 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004356 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004357 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004358 }
4359
4360 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4361 if (err < 0)
4362 goto unlock;
4363
4364 if (changed)
4365 err = new_settings(hdev, sk);
4366
4367 goto unlock;
4368 }
4369
Johan Hedberg333ae952015-03-17 13:48:47 +02004370 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4371 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004372 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4373 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004374 goto unlock;
4375 }
4376
4377 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4378 if (!cmd) {
4379 err = -ENOMEM;
4380 goto unlock;
4381 }
4382
4383 hci_req_init(&req, hdev);
4384
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004385 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004386 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004387 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004388 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004389
Florian Grandel7816b822015-06-18 03:16:45 +02004390 cancel_adv_timeout(hdev);
4391
Arman Uguray24b4f382015-03-23 15:57:12 -07004392 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004393 /* Switch to instance "0" for the Set Advertising setting.
4394 * We cannot use update_[adv|scan_rsp]_data() here as the
4395 * HCI_ADVERTISING flag is not yet set.
4396 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004397 hdev->cur_adv_instance = 0x00;
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05304398
4399 if (ext_adv_capable(hdev)) {
4400 __hci_req_start_ext_adv(&req, 0x00);
4401 } else {
4402 __hci_req_update_adv_data(&req, 0x00);
4403 __hci_req_update_scan_rsp_data(&req, 0x00);
4404 __hci_req_enable_advertising(&req);
4405 }
Arman Uguray24b4f382015-03-23 15:57:12 -07004406 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004407 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004408 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004409
4410 err = hci_req_run(&req, set_advertising_complete);
4411 if (err < 0)
4412 mgmt_pending_remove(cmd);
4413
4414unlock:
4415 hci_dev_unlock(hdev);
4416 return err;
4417}
4418
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004419static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4420 void *data, u16 len)
4421{
4422 struct mgmt_cp_set_static_address *cp = data;
4423 int err;
4424
4425 BT_DBG("%s", hdev->name);
4426
Marcel Holtmann62af4442013-10-02 22:10:32 -07004427 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004428 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4429 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004430
4431 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004432 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4433 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004434
4435 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4436 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004437 return mgmt_cmd_status(sk, hdev->id,
4438 MGMT_OP_SET_STATIC_ADDRESS,
4439 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004440
4441 /* Two most significant bits shall be set */
4442 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004443 return mgmt_cmd_status(sk, hdev->id,
4444 MGMT_OP_SET_STATIC_ADDRESS,
4445 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004446 }
4447
4448 hci_dev_lock(hdev);
4449
4450 bacpy(&hdev->static_addr, &cp->bdaddr);
4451
Marcel Holtmann93690c22015-03-06 10:11:21 -08004452 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4453 if (err < 0)
4454 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004455
Marcel Holtmann93690c22015-03-06 10:11:21 -08004456 err = new_settings(hdev, sk);
4457
4458unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004459 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004460 return err;
4461}
4462
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004463static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4464 void *data, u16 len)
4465{
4466 struct mgmt_cp_set_scan_params *cp = data;
4467 __u16 interval, window;
4468 int err;
4469
4470 BT_DBG("%s", hdev->name);
4471
4472 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004473 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4474 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004475
4476 interval = __le16_to_cpu(cp->interval);
4477
4478 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004479 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4480 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004481
4482 window = __le16_to_cpu(cp->window);
4483
4484 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004485 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4486 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004487
Marcel Holtmann899e1072013-10-14 09:55:32 -07004488 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004489 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4490 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004491
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004492 hci_dev_lock(hdev);
4493
4494 hdev->le_scan_interval = interval;
4495 hdev->le_scan_window = window;
4496
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004497 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4498 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004499
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004500 /* If background scan is running, restart it so new parameters are
4501 * loaded.
4502 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004503 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004504 hdev->discovery.state == DISCOVERY_STOPPED) {
4505 struct hci_request req;
4506
4507 hci_req_init(&req, hdev);
4508
4509 hci_req_add_le_scan_disable(&req);
4510 hci_req_add_le_passive_scan(&req);
4511
4512 hci_req_run(&req, NULL);
4513 }
4514
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004515 hci_dev_unlock(hdev);
4516
4517 return err;
4518}
4519
Marcel Holtmann1904a852015-01-11 13:50:44 -08004520static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4521 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004522{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004523 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004524
4525 BT_DBG("status 0x%02x", status);
4526
4527 hci_dev_lock(hdev);
4528
Johan Hedberg333ae952015-03-17 13:48:47 +02004529 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004530 if (!cmd)
4531 goto unlock;
4532
4533 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004534 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4535 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004536 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004537 struct mgmt_mode *cp = cmd->param;
4538
4539 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004540 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004541 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004542 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004543
Johan Hedberg33e38b32013-03-15 17:07:05 -05004544 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4545 new_settings(hdev, cmd->sk);
4546 }
4547
4548 mgmt_pending_remove(cmd);
4549
4550unlock:
4551 hci_dev_unlock(hdev);
4552}
4553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004554static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004555 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004556{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004557 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004558 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004559 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004560 int err;
4561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004562 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004563
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004564 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004565 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4567 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004568
Johan Hedberga7e80f22013-01-09 16:05:19 +02004569 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004570 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4571 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004572
Antti Julkuf6422ec2011-06-22 13:11:56 +03004573 hci_dev_lock(hdev);
4574
Johan Hedberg333ae952015-03-17 13:48:47 +02004575 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004576 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4577 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004578 goto unlock;
4579 }
4580
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004581 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004582 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4583 hdev);
4584 goto unlock;
4585 }
4586
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004587 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004588 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004589 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4590 hdev);
4591 new_settings(hdev, sk);
4592 goto unlock;
4593 }
4594
Johan Hedberg33e38b32013-03-15 17:07:05 -05004595 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4596 data, len);
4597 if (!cmd) {
4598 err = -ENOMEM;
4599 goto unlock;
4600 }
4601
4602 hci_req_init(&req, hdev);
4603
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004604 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004605
4606 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004607 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004608 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4609 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004610 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004611 }
4612
Johan Hedberg33e38b32013-03-15 17:07:05 -05004613unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004614 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004615
Antti Julkuf6422ec2011-06-22 13:11:56 +03004616 return err;
4617}
4618
Marcel Holtmann1904a852015-01-11 13:50:44 -08004619static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004620{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004621 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004622
4623 BT_DBG("status 0x%02x", status);
4624
4625 hci_dev_lock(hdev);
4626
Johan Hedberg333ae952015-03-17 13:48:47 +02004627 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004628 if (!cmd)
4629 goto unlock;
4630
4631 if (status) {
4632 u8 mgmt_err = mgmt_status(status);
4633
4634 /* We need to restore the flag if related HCI commands
4635 * failed.
4636 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004637 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004638
Johan Hedberga69e8372015-03-06 21:08:53 +02004639 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004640 } else {
4641 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4642 new_settings(hdev, cmd->sk);
4643 }
4644
4645 mgmt_pending_remove(cmd);
4646
4647unlock:
4648 hci_dev_unlock(hdev);
4649}
4650
4651static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4652{
4653 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004654 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004655 struct hci_request req;
4656 int err;
4657
4658 BT_DBG("request for %s", hdev->name);
4659
4660 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004661 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4662 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004664 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004665 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4666 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004667
4668 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004669 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4670 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004671
4672 hci_dev_lock(hdev);
4673
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004674 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004675 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4676 goto unlock;
4677 }
4678
4679 if (!hdev_is_powered(hdev)) {
4680 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004681 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4682 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4683 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4684 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4685 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004686 }
4687
Marcel Holtmannce05d602015-03-13 02:11:03 -07004688 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004689
4690 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4691 if (err < 0)
4692 goto unlock;
4693
4694 err = new_settings(hdev, sk);
4695 goto unlock;
4696 }
4697
4698 /* Reject disabling when powered on */
4699 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004700 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4701 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004702 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004703 } else {
4704 /* When configuring a dual-mode controller to operate
4705 * with LE only and using a static address, then switching
4706 * BR/EDR back on is not allowed.
4707 *
4708 * Dual-mode controllers shall operate with the public
4709 * address as its identity address for BR/EDR and LE. So
4710 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004711 *
4712 * The same restrictions applies when secure connections
4713 * has been enabled. For BR/EDR this is a controller feature
4714 * while for LE it is a host stack feature. This means that
4715 * switching BR/EDR back on when secure connections has been
4716 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004717 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004718 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004719 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004720 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004721 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4722 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004723 goto unlock;
4724 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004725 }
4726
Johan Hedberg333ae952015-03-17 13:48:47 +02004727 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004728 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4729 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004730 goto unlock;
4731 }
4732
4733 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4734 if (!cmd) {
4735 err = -ENOMEM;
4736 goto unlock;
4737 }
4738
Johan Hedbergf2252572015-11-18 12:49:20 +02004739 /* We need to flip the bit already here so that
4740 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004741 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004742 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004743
4744 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004745
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004746 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004747 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004748
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004749 /* Since only the advertising data flags will change, there
4750 * is no need to update the scan response data.
4751 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004752 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004753
Johan Hedberg0663ca22013-10-02 13:43:14 +03004754 err = hci_req_run(&req, set_bredr_complete);
4755 if (err < 0)
4756 mgmt_pending_remove(cmd);
4757
4758unlock:
4759 hci_dev_unlock(hdev);
4760 return err;
4761}
4762
Johan Hedberga1443f52015-01-23 15:42:46 +02004763static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4764{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004765 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004766 struct mgmt_mode *cp;
4767
4768 BT_DBG("%s status %u", hdev->name, status);
4769
4770 hci_dev_lock(hdev);
4771
Johan Hedberg333ae952015-03-17 13:48:47 +02004772 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004773 if (!cmd)
4774 goto unlock;
4775
4776 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004777 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4778 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004779 goto remove;
4780 }
4781
4782 cp = cmd->param;
4783
4784 switch (cp->val) {
4785 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004786 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4787 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004788 break;
4789 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004790 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004791 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004792 break;
4793 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004794 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4795 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004796 break;
4797 }
4798
4799 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4800 new_settings(hdev, cmd->sk);
4801
4802remove:
4803 mgmt_pending_remove(cmd);
4804unlock:
4805 hci_dev_unlock(hdev);
4806}
4807
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004808static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4809 void *data, u16 len)
4810{
4811 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004812 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004813 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004814 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004815 int err;
4816
4817 BT_DBG("request for %s", hdev->name);
4818
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004819 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004820 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004821 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4822 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004823
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004824 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004825 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004826 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004827 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4828 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004829
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004830 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004831 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004832 MGMT_STATUS_INVALID_PARAMS);
4833
4834 hci_dev_lock(hdev);
4835
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004836 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004837 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004838 bool changed;
4839
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004840 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004841 changed = !hci_dev_test_and_set_flag(hdev,
4842 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004843 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004844 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004845 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004846 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004847 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004848 changed = hci_dev_test_and_clear_flag(hdev,
4849 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004850 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004851 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004852
4853 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4854 if (err < 0)
4855 goto failed;
4856
4857 if (changed)
4858 err = new_settings(hdev, sk);
4859
4860 goto failed;
4861 }
4862
Johan Hedberg333ae952015-03-17 13:48:47 +02004863 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004864 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4865 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004866 goto failed;
4867 }
4868
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004869 val = !!cp->val;
4870
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004871 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4872 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004873 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4874 goto failed;
4875 }
4876
4877 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4878 if (!cmd) {
4879 err = -ENOMEM;
4880 goto failed;
4881 }
4882
Johan Hedberga1443f52015-01-23 15:42:46 +02004883 hci_req_init(&req, hdev);
4884 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4885 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004886 if (err < 0) {
4887 mgmt_pending_remove(cmd);
4888 goto failed;
4889 }
4890
4891failed:
4892 hci_dev_unlock(hdev);
4893 return err;
4894}
4895
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004896static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4897 void *data, u16 len)
4898{
4899 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004900 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004901 int err;
4902
4903 BT_DBG("request for %s", hdev->name);
4904
Johan Hedbergb97109792014-06-24 14:00:28 +03004905 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004906 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4907 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004908
4909 hci_dev_lock(hdev);
4910
4911 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004912 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004913 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004914 changed = hci_dev_test_and_clear_flag(hdev,
4915 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004916
Johan Hedbergb97109792014-06-24 14:00:28 +03004917 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004918 use_changed = !hci_dev_test_and_set_flag(hdev,
4919 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004920 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004921 use_changed = hci_dev_test_and_clear_flag(hdev,
4922 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004923
4924 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004925 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004926 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4927 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4928 sizeof(mode), &mode);
4929 }
4930
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004931 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4932 if (err < 0)
4933 goto unlock;
4934
4935 if (changed)
4936 err = new_settings(hdev, sk);
4937
4938unlock:
4939 hci_dev_unlock(hdev);
4940 return err;
4941}
4942
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004943static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4944 u16 len)
4945{
4946 struct mgmt_cp_set_privacy *cp = cp_data;
4947 bool changed;
4948 int err;
4949
4950 BT_DBG("request for %s", hdev->name);
4951
4952 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004953 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4954 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004955
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004956 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004957 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004959
4960 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004961 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4962 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004963
4964 hci_dev_lock(hdev);
4965
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004966 /* If user space supports this command it is also expected to
4967 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4968 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004969 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004970
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004971 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004972 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004973 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004974 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004975 if (cp->privacy == 0x02)
4976 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4977 else
4978 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004979 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004980 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004981 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004982 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004983 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004984 }
4985
4986 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4987 if (err < 0)
4988 goto unlock;
4989
4990 if (changed)
4991 err = new_settings(hdev, sk);
4992
4993unlock:
4994 hci_dev_unlock(hdev);
4995 return err;
4996}
4997
Johan Hedberg41edf162014-02-18 10:19:35 +02004998static bool irk_is_valid(struct mgmt_irk_info *irk)
4999{
5000 switch (irk->addr.type) {
5001 case BDADDR_LE_PUBLIC:
5002 return true;
5003
5004 case BDADDR_LE_RANDOM:
5005 /* Two most significant bits shall be set */
5006 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5007 return false;
5008 return true;
5009 }
5010
5011 return false;
5012}
5013
5014static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5015 u16 len)
5016{
5017 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005018 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5019 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005020 u16 irk_count, expected_len;
5021 int i, err;
5022
5023 BT_DBG("request for %s", hdev->name);
5024
5025 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005026 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5027 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005028
5029 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005030 if (irk_count > max_irk_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005031 bt_dev_err(hdev, "load_irks: too big irk_count value %u",
5032 irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005033 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5034 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005035 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005036
5037 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5038 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005039 bt_dev_err(hdev, "load_irks: expected %u bytes, got %u bytes",
5040 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005041 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5042 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005043 }
5044
5045 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5046
5047 for (i = 0; i < irk_count; i++) {
5048 struct mgmt_irk_info *key = &cp->irks[i];
5049
5050 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005051 return mgmt_cmd_status(sk, hdev->id,
5052 MGMT_OP_LOAD_IRKS,
5053 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005054 }
5055
5056 hci_dev_lock(hdev);
5057
5058 hci_smp_irks_clear(hdev);
5059
5060 for (i = 0; i < irk_count; i++) {
5061 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02005062
Johan Hedberg85813a72015-10-21 18:02:59 +03005063 hci_add_irk(hdev, &irk->addr.bdaddr,
5064 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02005065 BDADDR_ANY);
5066 }
5067
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005068 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005069
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005070 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005071
5072 hci_dev_unlock(hdev);
5073
5074 return err;
5075}
5076
Johan Hedberg3f706b72013-01-20 14:27:16 +02005077static bool ltk_is_valid(struct mgmt_ltk_info *key)
5078{
5079 if (key->master != 0x00 && key->master != 0x01)
5080 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005081
5082 switch (key->addr.type) {
5083 case BDADDR_LE_PUBLIC:
5084 return true;
5085
5086 case BDADDR_LE_RANDOM:
5087 /* Two most significant bits shall be set */
5088 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5089 return false;
5090 return true;
5091 }
5092
5093 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005094}
5095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005096static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005097 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005098{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005099 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005100 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5101 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005102 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005103 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005104
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005105 BT_DBG("request for %s", hdev->name);
5106
5107 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005108 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5109 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005110
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005111 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005112 if (key_count > max_key_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005113 bt_dev_err(hdev, "load_ltks: too big key_count value %u",
5114 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005115 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5116 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005117 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005118
5119 expected_len = sizeof(*cp) + key_count *
5120 sizeof(struct mgmt_ltk_info);
5121 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005122 bt_dev_err(hdev, "load_keys: expected %u bytes, got %u bytes",
5123 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005124 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5125 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005126 }
5127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005128 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005129
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005130 for (i = 0; i < key_count; i++) {
5131 struct mgmt_ltk_info *key = &cp->keys[i];
5132
Johan Hedberg3f706b72013-01-20 14:27:16 +02005133 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005134 return mgmt_cmd_status(sk, hdev->id,
5135 MGMT_OP_LOAD_LONG_TERM_KEYS,
5136 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005137 }
5138
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005139 hci_dev_lock(hdev);
5140
5141 hci_smp_ltks_clear(hdev);
5142
5143 for (i = 0; i < key_count; i++) {
5144 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03005145 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005146
Johan Hedberg61b43352014-05-29 19:36:53 +03005147 switch (key->type) {
5148 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005149 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005150 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005151 break;
5152 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005153 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005154 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005155 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005156 case MGMT_LTK_P256_UNAUTH:
5157 authenticated = 0x00;
5158 type = SMP_LTK_P256;
5159 break;
5160 case MGMT_LTK_P256_AUTH:
5161 authenticated = 0x01;
5162 type = SMP_LTK_P256;
5163 break;
5164 case MGMT_LTK_P256_DEBUG:
5165 authenticated = 0x00;
5166 type = SMP_LTK_P256_DEBUG;
Gustavo A. R. Silva9ea471322018-03-30 16:05:06 -05005167 /* fall through */
Johan Hedberg61b43352014-05-29 19:36:53 +03005168 default:
5169 continue;
5170 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005171
Johan Hedberg85813a72015-10-21 18:02:59 +03005172 hci_add_ltk(hdev, &key->addr.bdaddr,
5173 le_addr_type(key->addr.type), type, authenticated,
5174 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005175 }
5176
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005177 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005178 NULL, 0);
5179
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005180 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005181
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005182 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005183}
5184
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005185static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005186{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005187 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005188 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005189 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005190
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005191 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005192
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005193 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005194 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005195 rp.tx_power = conn->tx_power;
5196 rp.max_tx_power = conn->max_tx_power;
5197 } else {
5198 rp.rssi = HCI_RSSI_INVALID;
5199 rp.tx_power = HCI_TX_POWER_INVALID;
5200 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005201 }
5202
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005203 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5204 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005205
5206 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005207 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005208
5209 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005210}
5211
Marcel Holtmann1904a852015-01-11 13:50:44 -08005212static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5213 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005214{
5215 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005216 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005217 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005218 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005219 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005220
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005221 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005222
5223 hci_dev_lock(hdev);
5224
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005225 /* Commands sent in request are either Read RSSI or Read Transmit Power
5226 * Level so we check which one was last sent to retrieve connection
5227 * handle. Both commands have handle as first parameter so it's safe to
5228 * cast data on the same command struct.
5229 *
5230 * First command sent is always Read RSSI and we fail only if it fails.
5231 * In other case we simply override error to indicate success as we
5232 * already remembered if TX power value is actually valid.
5233 */
5234 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5235 if (!cp) {
5236 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005237 status = MGMT_STATUS_SUCCESS;
5238 } else {
5239 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005240 }
5241
5242 if (!cp) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005243 bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005244 goto unlock;
5245 }
5246
5247 handle = __le16_to_cpu(cp->handle);
5248 conn = hci_conn_hash_lookup_handle(hdev, handle);
5249 if (!conn) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005250 bt_dev_err(hdev, "unknown handle (%d) in conn_info response",
5251 handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005252 goto unlock;
5253 }
5254
Johan Hedberg333ae952015-03-17 13:48:47 +02005255 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005256 if (!cmd)
5257 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005258
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005259 cmd->cmd_complete(cmd, status);
5260 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005261
5262unlock:
5263 hci_dev_unlock(hdev);
5264}
5265
5266static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5267 u16 len)
5268{
5269 struct mgmt_cp_get_conn_info *cp = data;
5270 struct mgmt_rp_get_conn_info rp;
5271 struct hci_conn *conn;
5272 unsigned long conn_info_age;
5273 int err = 0;
5274
5275 BT_DBG("%s", hdev->name);
5276
5277 memset(&rp, 0, sizeof(rp));
5278 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5279 rp.addr.type = cp->addr.type;
5280
5281 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005282 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5283 MGMT_STATUS_INVALID_PARAMS,
5284 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005285
5286 hci_dev_lock(hdev);
5287
5288 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005289 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5290 MGMT_STATUS_NOT_POWERED, &rp,
5291 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005292 goto unlock;
5293 }
5294
5295 if (cp->addr.type == BDADDR_BREDR)
5296 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5297 &cp->addr.bdaddr);
5298 else
5299 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5300
5301 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005302 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5303 MGMT_STATUS_NOT_CONNECTED, &rp,
5304 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005305 goto unlock;
5306 }
5307
Johan Hedberg333ae952015-03-17 13:48:47 +02005308 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005309 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5310 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005311 goto unlock;
5312 }
5313
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005314 /* To avoid client trying to guess when to poll again for information we
5315 * calculate conn info age as random value between min/max set in hdev.
5316 */
5317 conn_info_age = hdev->conn_info_min_age +
5318 prandom_u32_max(hdev->conn_info_max_age -
5319 hdev->conn_info_min_age);
5320
5321 /* Query controller to refresh cached values if they are too old or were
5322 * never read.
5323 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005324 if (time_after(jiffies, conn->conn_info_timestamp +
5325 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005326 !conn->conn_info_timestamp) {
5327 struct hci_request req;
5328 struct hci_cp_read_tx_power req_txp_cp;
5329 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005330 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005331
5332 hci_req_init(&req, hdev);
5333 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5334 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5335 &req_rssi_cp);
5336
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005337 /* For LE links TX power does not change thus we don't need to
5338 * query for it once value is known.
5339 */
5340 if (!bdaddr_type_is_le(cp->addr.type) ||
5341 conn->tx_power == HCI_TX_POWER_INVALID) {
5342 req_txp_cp.handle = cpu_to_le16(conn->handle);
5343 req_txp_cp.type = 0x00;
5344 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5345 sizeof(req_txp_cp), &req_txp_cp);
5346 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005347
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005348 /* Max TX power needs to be read only once per connection */
5349 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5350 req_txp_cp.handle = cpu_to_le16(conn->handle);
5351 req_txp_cp.type = 0x01;
5352 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5353 sizeof(req_txp_cp), &req_txp_cp);
5354 }
5355
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005356 err = hci_req_run(&req, conn_info_refresh_complete);
5357 if (err < 0)
5358 goto unlock;
5359
5360 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5361 data, len);
5362 if (!cmd) {
5363 err = -ENOMEM;
5364 goto unlock;
5365 }
5366
5367 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005368 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005369 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005370
5371 conn->conn_info_timestamp = jiffies;
5372 } else {
5373 /* Cache is valid, just reply with values cached in hci_conn */
5374 rp.rssi = conn->rssi;
5375 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005376 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005377
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005378 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5379 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005380 }
5381
5382unlock:
5383 hci_dev_unlock(hdev);
5384 return err;
5385}
5386
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005387static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005388{
5389 struct hci_conn *conn = cmd->user_data;
5390 struct mgmt_rp_get_clock_info rp;
5391 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005392 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005393
5394 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005395 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005396
5397 if (status)
5398 goto complete;
5399
5400 hdev = hci_dev_get(cmd->index);
5401 if (hdev) {
5402 rp.local_clock = cpu_to_le32(hdev->clock);
5403 hci_dev_put(hdev);
5404 }
5405
5406 if (conn) {
5407 rp.piconet_clock = cpu_to_le32(conn->clock);
5408 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5409 }
5410
5411complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005412 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5413 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005414
5415 if (conn) {
5416 hci_conn_drop(conn);
5417 hci_conn_put(conn);
5418 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005419
5420 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005421}
5422
Marcel Holtmann1904a852015-01-11 13:50:44 -08005423static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005424{
Johan Hedberg95868422014-06-28 17:54:07 +03005425 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005426 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005427 struct hci_conn *conn;
5428
5429 BT_DBG("%s status %u", hdev->name, status);
5430
5431 hci_dev_lock(hdev);
5432
5433 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5434 if (!hci_cp)
5435 goto unlock;
5436
5437 if (hci_cp->which) {
5438 u16 handle = __le16_to_cpu(hci_cp->handle);
5439 conn = hci_conn_hash_lookup_handle(hdev, handle);
5440 } else {
5441 conn = NULL;
5442 }
5443
Johan Hedberg333ae952015-03-17 13:48:47 +02005444 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005445 if (!cmd)
5446 goto unlock;
5447
Johan Hedberg69487372014-12-05 13:36:07 +02005448 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005449 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005450
5451unlock:
5452 hci_dev_unlock(hdev);
5453}
5454
5455static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5456 u16 len)
5457{
5458 struct mgmt_cp_get_clock_info *cp = data;
5459 struct mgmt_rp_get_clock_info rp;
5460 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005461 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005462 struct hci_request req;
5463 struct hci_conn *conn;
5464 int err;
5465
5466 BT_DBG("%s", hdev->name);
5467
5468 memset(&rp, 0, sizeof(rp));
5469 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5470 rp.addr.type = cp->addr.type;
5471
5472 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005473 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5474 MGMT_STATUS_INVALID_PARAMS,
5475 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005476
5477 hci_dev_lock(hdev);
5478
5479 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005480 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5481 MGMT_STATUS_NOT_POWERED, &rp,
5482 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005483 goto unlock;
5484 }
5485
5486 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5487 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5488 &cp->addr.bdaddr);
5489 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005490 err = mgmt_cmd_complete(sk, hdev->id,
5491 MGMT_OP_GET_CLOCK_INFO,
5492 MGMT_STATUS_NOT_CONNECTED,
5493 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005494 goto unlock;
5495 }
5496 } else {
5497 conn = NULL;
5498 }
5499
5500 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5501 if (!cmd) {
5502 err = -ENOMEM;
5503 goto unlock;
5504 }
5505
Johan Hedberg69487372014-12-05 13:36:07 +02005506 cmd->cmd_complete = clock_info_cmd_complete;
5507
Johan Hedberg95868422014-06-28 17:54:07 +03005508 hci_req_init(&req, hdev);
5509
5510 memset(&hci_cp, 0, sizeof(hci_cp));
5511 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5512
5513 if (conn) {
5514 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005515 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005516
5517 hci_cp.handle = cpu_to_le16(conn->handle);
5518 hci_cp.which = 0x01; /* Piconet clock */
5519 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5520 }
5521
5522 err = hci_req_run(&req, get_clock_info_complete);
5523 if (err < 0)
5524 mgmt_pending_remove(cmd);
5525
5526unlock:
5527 hci_dev_unlock(hdev);
5528 return err;
5529}
5530
Johan Hedberg5a154e62014-12-19 22:26:02 +02005531static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5532{
5533 struct hci_conn *conn;
5534
5535 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5536 if (!conn)
5537 return false;
5538
5539 if (conn->dst_type != type)
5540 return false;
5541
5542 if (conn->state != BT_CONNECTED)
5543 return false;
5544
5545 return true;
5546}
5547
5548/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005549static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005550 u8 addr_type, u8 auto_connect)
5551{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005552 struct hci_conn_params *params;
5553
5554 params = hci_conn_params_add(hdev, addr, addr_type);
5555 if (!params)
5556 return -EIO;
5557
5558 if (params->auto_connect == auto_connect)
5559 return 0;
5560
5561 list_del_init(&params->action);
5562
5563 switch (auto_connect) {
5564 case HCI_AUTO_CONN_DISABLED:
5565 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005566 /* If auto connect is being disabled when we're trying to
5567 * connect to device, keep connecting.
5568 */
5569 if (params->explicit_connect)
5570 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005571 break;
5572 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005573 if (params->explicit_connect)
5574 list_add(&params->action, &hdev->pend_le_conns);
5575 else
5576 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005577 break;
5578 case HCI_AUTO_CONN_DIRECT:
5579 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005580 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005581 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005582 break;
5583 }
5584
5585 params->auto_connect = auto_connect;
5586
5587 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5588 auto_connect);
5589
5590 return 0;
5591}
5592
Marcel Holtmann8afef092014-06-29 22:28:34 +02005593static void device_added(struct sock *sk, struct hci_dev *hdev,
5594 bdaddr_t *bdaddr, u8 type, u8 action)
5595{
5596 struct mgmt_ev_device_added ev;
5597
5598 bacpy(&ev.addr.bdaddr, bdaddr);
5599 ev.addr.type = type;
5600 ev.action = action;
5601
5602 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5603}
5604
Marcel Holtmann2faade52014-06-29 19:44:03 +02005605static int add_device(struct sock *sk, struct hci_dev *hdev,
5606 void *data, u16 len)
5607{
5608 struct mgmt_cp_add_device *cp = data;
5609 u8 auto_conn, addr_type;
5610 int err;
5611
5612 BT_DBG("%s", hdev->name);
5613
Johan Hedberg66593582014-07-09 12:59:14 +03005614 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005615 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005616 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5617 MGMT_STATUS_INVALID_PARAMS,
5618 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005619
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005620 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005621 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5622 MGMT_STATUS_INVALID_PARAMS,
5623 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005624
5625 hci_dev_lock(hdev);
5626
Johan Hedberg66593582014-07-09 12:59:14 +03005627 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005628 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005629 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005630 err = mgmt_cmd_complete(sk, hdev->id,
5631 MGMT_OP_ADD_DEVICE,
5632 MGMT_STATUS_INVALID_PARAMS,
5633 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005634 goto unlock;
5635 }
5636
5637 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5638 cp->addr.type);
5639 if (err)
5640 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005641
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005642 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005643
Johan Hedberg66593582014-07-09 12:59:14 +03005644 goto added;
5645 }
5646
Johan Hedberg85813a72015-10-21 18:02:59 +03005647 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005648
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005649 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005650 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005651 else if (cp->action == 0x01)
5652 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005653 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005654 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005655
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005656 /* Kernel internally uses conn_params with resolvable private
5657 * address, but Add Device allows only identity addresses.
5658 * Make sure it is enforced before calling
5659 * hci_conn_params_lookup.
5660 */
5661 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005662 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5663 MGMT_STATUS_INVALID_PARAMS,
5664 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005665 goto unlock;
5666 }
5667
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005668 /* If the connection parameters don't exist for this device,
5669 * they will be created and configured with defaults.
5670 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005671 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005672 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005673 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5674 MGMT_STATUS_FAILED, &cp->addr,
5675 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005676 goto unlock;
5677 }
5678
Johan Hedberg51d7a942015-11-11 08:11:18 +02005679 hci_update_background_scan(hdev);
5680
Johan Hedberg66593582014-07-09 12:59:14 +03005681added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005682 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5683
Johan Hedberg51d7a942015-11-11 08:11:18 +02005684 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5685 MGMT_STATUS_SUCCESS, &cp->addr,
5686 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005687
5688unlock:
5689 hci_dev_unlock(hdev);
5690 return err;
5691}
5692
Marcel Holtmann8afef092014-06-29 22:28:34 +02005693static void device_removed(struct sock *sk, struct hci_dev *hdev,
5694 bdaddr_t *bdaddr, u8 type)
5695{
5696 struct mgmt_ev_device_removed ev;
5697
5698 bacpy(&ev.addr.bdaddr, bdaddr);
5699 ev.addr.type = type;
5700
5701 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5702}
5703
Marcel Holtmann2faade52014-06-29 19:44:03 +02005704static int remove_device(struct sock *sk, struct hci_dev *hdev,
5705 void *data, u16 len)
5706{
5707 struct mgmt_cp_remove_device *cp = data;
5708 int err;
5709
5710 BT_DBG("%s", hdev->name);
5711
5712 hci_dev_lock(hdev);
5713
5714 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005715 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005716 u8 addr_type;
5717
Johan Hedberg66593582014-07-09 12:59:14 +03005718 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005719 err = mgmt_cmd_complete(sk, hdev->id,
5720 MGMT_OP_REMOVE_DEVICE,
5721 MGMT_STATUS_INVALID_PARAMS,
5722 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005723 goto unlock;
5724 }
5725
Johan Hedberg66593582014-07-09 12:59:14 +03005726 if (cp->addr.type == BDADDR_BREDR) {
5727 err = hci_bdaddr_list_del(&hdev->whitelist,
5728 &cp->addr.bdaddr,
5729 cp->addr.type);
5730 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005731 err = mgmt_cmd_complete(sk, hdev->id,
5732 MGMT_OP_REMOVE_DEVICE,
5733 MGMT_STATUS_INVALID_PARAMS,
5734 &cp->addr,
5735 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005736 goto unlock;
5737 }
5738
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005739 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005740
Johan Hedberg66593582014-07-09 12:59:14 +03005741 device_removed(sk, hdev, &cp->addr.bdaddr,
5742 cp->addr.type);
5743 goto complete;
5744 }
5745
Johan Hedberg85813a72015-10-21 18:02:59 +03005746 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005747
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005748 /* Kernel internally uses conn_params with resolvable private
5749 * address, but Remove Device allows only identity addresses.
5750 * Make sure it is enforced before calling
5751 * hci_conn_params_lookup.
5752 */
5753 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
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));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005758 goto unlock;
5759 }
5760
Johan Hedbergc71593d2014-07-02 17:37:28 +03005761 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5762 addr_type);
5763 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005764 err = mgmt_cmd_complete(sk, hdev->id,
5765 MGMT_OP_REMOVE_DEVICE,
5766 MGMT_STATUS_INVALID_PARAMS,
5767 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005768 goto unlock;
5769 }
5770
Johan Hedberg679d2b62015-10-16 10:07:52 +03005771 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5772 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005773 err = mgmt_cmd_complete(sk, hdev->id,
5774 MGMT_OP_REMOVE_DEVICE,
5775 MGMT_STATUS_INVALID_PARAMS,
5776 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005777 goto unlock;
5778 }
5779
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005780 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005781 list_del(&params->list);
5782 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005783 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005784
5785 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005786 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005787 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005788 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005789
Marcel Holtmann2faade52014-06-29 19:44:03 +02005790 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005791 err = mgmt_cmd_complete(sk, hdev->id,
5792 MGMT_OP_REMOVE_DEVICE,
5793 MGMT_STATUS_INVALID_PARAMS,
5794 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005795 goto unlock;
5796 }
5797
Johan Hedberg66593582014-07-09 12:59:14 +03005798 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5799 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5800 list_del(&b->list);
5801 kfree(b);
5802 }
5803
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005804 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005805
Johan Hedberg19de0822014-07-06 13:06:51 +03005806 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5807 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5808 continue;
5809 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005810 if (p->explicit_connect) {
5811 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5812 continue;
5813 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005814 list_del(&p->action);
5815 list_del(&p->list);
5816 kfree(p);
5817 }
5818
5819 BT_DBG("All LE connection parameters were removed");
5820
Johan Hedberg51d7a942015-11-11 08:11:18 +02005821 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005822 }
5823
Johan Hedberg66593582014-07-09 12:59:14 +03005824complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005825 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5826 MGMT_STATUS_SUCCESS, &cp->addr,
5827 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005828unlock:
5829 hci_dev_unlock(hdev);
5830 return err;
5831}
5832
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005833static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5834 u16 len)
5835{
5836 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005837 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5838 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005839 u16 param_count, expected_len;
5840 int i;
5841
5842 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005843 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5844 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005845
5846 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005847 if (param_count > max_param_count) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005848 bt_dev_err(hdev, "load_conn_param: too big param_count value %u",
5849 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005850 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005852 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005853
5854 expected_len = sizeof(*cp) + param_count *
5855 sizeof(struct mgmt_conn_param);
5856 if (expected_len != len) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005857 bt_dev_err(hdev, "load_conn_param: expected %u bytes, got %u bytes",
5858 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005859 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5860 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005861 }
5862
5863 BT_DBG("%s param_count %u", hdev->name, param_count);
5864
5865 hci_dev_lock(hdev);
5866
5867 hci_conn_params_clear_disabled(hdev);
5868
5869 for (i = 0; i < param_count; i++) {
5870 struct mgmt_conn_param *param = &cp->params[i];
5871 struct hci_conn_params *hci_param;
5872 u16 min, max, latency, timeout;
5873 u8 addr_type;
5874
5875 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5876 param->addr.type);
5877
5878 if (param->addr.type == BDADDR_LE_PUBLIC) {
5879 addr_type = ADDR_LE_DEV_PUBLIC;
5880 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5881 addr_type = ADDR_LE_DEV_RANDOM;
5882 } else {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005883 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005884 continue;
5885 }
5886
5887 min = le16_to_cpu(param->min_interval);
5888 max = le16_to_cpu(param->max_interval);
5889 latency = le16_to_cpu(param->latency);
5890 timeout = le16_to_cpu(param->timeout);
5891
5892 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5893 min, max, latency, timeout);
5894
5895 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005896 bt_dev_err(hdev, "ignoring invalid connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005897 continue;
5898 }
5899
5900 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5901 addr_type);
5902 if (!hci_param) {
Marcel Holtmann2064ee32017-10-30 10:42:59 +01005903 bt_dev_err(hdev, "failed to add connection parameters");
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005904 continue;
5905 }
5906
5907 hci_param->conn_min_interval = min;
5908 hci_param->conn_max_interval = max;
5909 hci_param->conn_latency = latency;
5910 hci_param->supervision_timeout = timeout;
5911 }
5912
5913 hci_dev_unlock(hdev);
5914
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005915 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5916 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005917}
5918
Marcel Holtmanndbece372014-07-04 18:11:55 +02005919static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5920 void *data, u16 len)
5921{
5922 struct mgmt_cp_set_external_config *cp = data;
5923 bool changed;
5924 int err;
5925
5926 BT_DBG("%s", hdev->name);
5927
5928 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005929 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5930 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005931
5932 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005933 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5934 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005935
5936 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005937 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5938 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005939
5940 hci_dev_lock(hdev);
5941
5942 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005943 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005944 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005945 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005946
5947 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5948 if (err < 0)
5949 goto unlock;
5950
5951 if (!changed)
5952 goto unlock;
5953
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005954 err = new_options(hdev, sk);
5955
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005956 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005957 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005958
Marcel Holtmann516018a2015-03-13 02:11:04 -07005959 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005960 hci_dev_set_flag(hdev, HCI_CONFIG);
5961 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005962
5963 queue_work(hdev->req_workqueue, &hdev->power_on);
5964 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005965 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005966 mgmt_index_added(hdev);
5967 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005968 }
5969
5970unlock:
5971 hci_dev_unlock(hdev);
5972 return err;
5973}
5974
Marcel Holtmann9713c172014-07-06 12:11:15 +02005975static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5976 void *data, u16 len)
5977{
5978 struct mgmt_cp_set_public_address *cp = data;
5979 bool changed;
5980 int err;
5981
5982 BT_DBG("%s", hdev->name);
5983
5984 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005985 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5986 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005987
5988 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005989 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5990 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005991
5992 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005993 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5994 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005995
5996 hci_dev_lock(hdev);
5997
5998 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5999 bacpy(&hdev->public_addr, &cp->bdaddr);
6000
6001 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6002 if (err < 0)
6003 goto unlock;
6004
6005 if (!changed)
6006 goto unlock;
6007
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006008 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006009 err = new_options(hdev, sk);
6010
6011 if (is_configured(hdev)) {
6012 mgmt_index_removed(hdev);
6013
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006014 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006015
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006016 hci_dev_set_flag(hdev, HCI_CONFIG);
6017 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006018
6019 queue_work(hdev->req_workqueue, &hdev->power_on);
6020 }
6021
6022unlock:
6023 hci_dev_unlock(hdev);
6024 return err;
6025}
6026
Johan Hedberg40f66c02015-04-07 21:52:22 +03006027static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6028 u16 opcode, struct sk_buff *skb)
6029{
6030 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6031 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6032 u8 *h192, *r192, *h256, *r256;
6033 struct mgmt_pending_cmd *cmd;
6034 u16 eir_len;
6035 int err;
6036
6037 BT_DBG("%s status %u", hdev->name, status);
6038
6039 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6040 if (!cmd)
6041 return;
6042
6043 mgmt_cp = cmd->param;
6044
6045 if (status) {
6046 status = mgmt_status(status);
6047 eir_len = 0;
6048
6049 h192 = NULL;
6050 r192 = NULL;
6051 h256 = NULL;
6052 r256 = NULL;
6053 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6054 struct hci_rp_read_local_oob_data *rp;
6055
6056 if (skb->len != sizeof(*rp)) {
6057 status = MGMT_STATUS_FAILED;
6058 eir_len = 0;
6059 } else {
6060 status = MGMT_STATUS_SUCCESS;
6061 rp = (void *)skb->data;
6062
6063 eir_len = 5 + 18 + 18;
6064 h192 = rp->hash;
6065 r192 = rp->rand;
6066 h256 = NULL;
6067 r256 = NULL;
6068 }
6069 } else {
6070 struct hci_rp_read_local_oob_ext_data *rp;
6071
6072 if (skb->len != sizeof(*rp)) {
6073 status = MGMT_STATUS_FAILED;
6074 eir_len = 0;
6075 } else {
6076 status = MGMT_STATUS_SUCCESS;
6077 rp = (void *)skb->data;
6078
6079 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6080 eir_len = 5 + 18 + 18;
6081 h192 = NULL;
6082 r192 = NULL;
6083 } else {
6084 eir_len = 5 + 18 + 18 + 18 + 18;
6085 h192 = rp->hash192;
6086 r192 = rp->rand192;
6087 }
6088
6089 h256 = rp->hash256;
6090 r256 = rp->rand256;
6091 }
6092 }
6093
6094 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6095 if (!mgmt_rp)
6096 goto done;
6097
6098 if (status)
6099 goto send_rsp;
6100
6101 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6102 hdev->dev_class, 3);
6103
6104 if (h192 && r192) {
6105 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6106 EIR_SSP_HASH_C192, h192, 16);
6107 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6108 EIR_SSP_RAND_R192, r192, 16);
6109 }
6110
6111 if (h256 && r256) {
6112 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6113 EIR_SSP_HASH_C256, h256, 16);
6114 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6115 EIR_SSP_RAND_R256, r256, 16);
6116 }
6117
6118send_rsp:
6119 mgmt_rp->type = mgmt_cp->type;
6120 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6121
6122 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6123 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6124 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6125 if (err < 0 || status)
6126 goto done;
6127
6128 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6129
6130 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6131 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6132 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6133done:
6134 kfree(mgmt_rp);
6135 mgmt_pending_remove(cmd);
6136}
6137
6138static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6139 struct mgmt_cp_read_local_oob_ext_data *cp)
6140{
6141 struct mgmt_pending_cmd *cmd;
6142 struct hci_request req;
6143 int err;
6144
6145 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6146 cp, sizeof(*cp));
6147 if (!cmd)
6148 return -ENOMEM;
6149
6150 hci_req_init(&req, hdev);
6151
6152 if (bredr_sc_enabled(hdev))
6153 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6154 else
6155 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6156
6157 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6158 if (err < 0) {
6159 mgmt_pending_remove(cmd);
6160 return err;
6161 }
6162
6163 return 0;
6164}
6165
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006166static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6167 void *data, u16 data_len)
6168{
6169 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6170 struct mgmt_rp_read_local_oob_ext_data *rp;
6171 size_t rp_len;
6172 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006173 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006174 int err;
6175
6176 BT_DBG("%s", hdev->name);
6177
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006178 if (hdev_is_powered(hdev)) {
6179 switch (cp->type) {
6180 case BIT(BDADDR_BREDR):
6181 status = mgmt_bredr_support(hdev);
6182 if (status)
6183 eir_len = 0;
6184 else
6185 eir_len = 5;
6186 break;
6187 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6188 status = mgmt_le_support(hdev);
6189 if (status)
6190 eir_len = 0;
6191 else
6192 eir_len = 9 + 3 + 18 + 18 + 3;
6193 break;
6194 default:
6195 status = MGMT_STATUS_INVALID_PARAMS;
6196 eir_len = 0;
6197 break;
6198 }
6199 } else {
6200 status = MGMT_STATUS_NOT_POWERED;
6201 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006202 }
6203
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006204 rp_len = sizeof(*rp) + eir_len;
6205 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006206 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006207 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006208
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006209 if (status)
6210 goto complete;
6211
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006212 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006213
6214 eir_len = 0;
6215 switch (cp->type) {
6216 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006217 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6218 err = read_local_ssp_oob_req(hdev, sk, cp);
6219 hci_dev_unlock(hdev);
6220 if (!err)
6221 goto done;
6222
6223 status = MGMT_STATUS_FAILED;
6224 goto complete;
6225 } else {
6226 eir_len = eir_append_data(rp->eir, eir_len,
6227 EIR_CLASS_OF_DEV,
6228 hdev->dev_class, 3);
6229 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006230 break;
6231 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006232 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6233 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006234 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006235 status = MGMT_STATUS_FAILED;
6236 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006237 }
6238
Marcel Holtmanne2135682015-04-02 12:00:58 -07006239 /* This should return the active RPA, but since the RPA
6240 * is only programmed on demand, it is really hard to fill
6241 * this in at the moment. For now disallow retrieving
6242 * local out-of-band data when privacy is in use.
6243 *
6244 * Returning the identity address will not help here since
6245 * pairing happens before the identity resolving key is
6246 * known and thus the connection establishment happens
6247 * based on the RPA and not the identity address.
6248 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006249 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006250 hci_dev_unlock(hdev);
6251 status = MGMT_STATUS_REJECTED;
6252 goto complete;
6253 }
6254
6255 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6256 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6257 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6258 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006259 memcpy(addr, &hdev->static_addr, 6);
6260 addr[6] = 0x01;
6261 } else {
6262 memcpy(addr, &hdev->bdaddr, 6);
6263 addr[6] = 0x00;
6264 }
6265
6266 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6267 addr, sizeof(addr));
6268
6269 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6270 role = 0x02;
6271 else
6272 role = 0x01;
6273
6274 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6275 &role, sizeof(role));
6276
Marcel Holtmann5082a592015-03-16 12:39:00 -07006277 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6278 eir_len = eir_append_data(rp->eir, eir_len,
6279 EIR_LE_SC_CONFIRM,
6280 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006281
Marcel Holtmann5082a592015-03-16 12:39:00 -07006282 eir_len = eir_append_data(rp->eir, eir_len,
6283 EIR_LE_SC_RANDOM,
6284 rand, sizeof(rand));
6285 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006286
Johan Hedbergf2252572015-11-18 12:49:20 +02006287 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006288
6289 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6290 flags |= LE_AD_NO_BREDR;
6291
6292 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6293 &flags, sizeof(flags));
6294 break;
6295 }
6296
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006297 hci_dev_unlock(hdev);
6298
Marcel Holtmann72000df2015-03-16 16:11:21 -07006299 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6300
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006301 status = MGMT_STATUS_SUCCESS;
6302
6303complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006304 rp->type = cp->type;
6305 rp->eir_len = cpu_to_le16(eir_len);
6306
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006307 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006308 status, rp, sizeof(*rp) + eir_len);
6309 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006310 goto done;
6311
6312 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6313 rp, sizeof(*rp) + eir_len,
6314 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006315
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006316done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006317 kfree(rp);
6318
6319 return err;
6320}
6321
Arman Uguray089fa8c2015-03-25 18:53:45 -07006322static u32 get_supported_adv_flags(struct hci_dev *hdev)
6323{
6324 u32 flags = 0;
6325
6326 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6327 flags |= MGMT_ADV_FLAG_DISCOV;
6328 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6329 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006330 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006331 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006332
Jaganath Kanakkasseryde181e82018-07-19 17:09:41 +05306333 /* In extended adv TX_POWER returned from Set Adv Param
6334 * will be always valid.
6335 */
6336 if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
6337 ext_adv_capable(hdev))
Arman Uguray089fa8c2015-03-25 18:53:45 -07006338 flags |= MGMT_ADV_FLAG_TX_POWER;
6339
6340 return flags;
6341}
6342
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006343static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6344 void *data, u16 data_len)
6345{
6346 struct mgmt_rp_read_adv_features *rp;
6347 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006348 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02006349 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006350 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006351 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006352
6353 BT_DBG("%s", hdev->name);
6354
Arman Uguray089fa8c2015-03-25 18:53:45 -07006355 if (!lmp_le_capable(hdev))
6356 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6357 MGMT_STATUS_REJECTED);
6358
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006359 hci_dev_lock(hdev);
6360
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006361 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006362 rp = kmalloc(rp_len, GFP_ATOMIC);
6363 if (!rp) {
6364 hci_dev_unlock(hdev);
6365 return -ENOMEM;
6366 }
6367
Arman Uguray089fa8c2015-03-25 18:53:45 -07006368 supported_flags = get_supported_adv_flags(hdev);
6369
6370 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006371 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6372 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006373 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006374 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006375
Johan Hedberg02c04afe2015-11-26 12:15:58 +02006376 instance = rp->instance;
6377 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6378 *instance = adv_instance->instance;
6379 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006380 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006381
6382 hci_dev_unlock(hdev);
6383
6384 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6385 MGMT_STATUS_SUCCESS, rp, rp_len);
6386
6387 kfree(rp);
6388
6389 return err;
6390}
6391
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006392static u8 calculate_name_len(struct hci_dev *hdev)
6393{
6394 u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
6395
6396 return append_local_name(hdev, buf, 0);
6397}
6398
6399static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
6400 bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006401{
Arman Uguray4117ed72015-03-23 15:57:14 -07006402 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006403
Marcel Holtmann31a32482015-11-19 16:16:42 +01006404 if (is_adv_data) {
6405 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6406 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006407 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006408 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006409
Szymon Janc2bb368702016-09-18 12:50:05 +02006410 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006411 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006412 } else {
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006413 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006414 max_len -= calculate_name_len(hdev);
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006415
Szymon Janc2bb368702016-09-18 12:50:05 +02006416 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006417 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006418 }
6419
Szymon Janc2bb368702016-09-18 12:50:05 +02006420 return max_len;
6421}
6422
6423static bool flags_managed(u32 adv_flags)
6424{
6425 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6426 MGMT_ADV_FLAG_LIMITED_DISCOV |
6427 MGMT_ADV_FLAG_MANAGED_FLAGS);
6428}
6429
6430static bool tx_power_managed(u32 adv_flags)
6431{
6432 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6433}
6434
6435static bool name_managed(u32 adv_flags)
6436{
6437 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6438}
6439
6440static bool appearance_managed(u32 adv_flags)
6441{
6442 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6443}
6444
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006445static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6446 u8 len, bool is_adv_data)
Szymon Janc2bb368702016-09-18 12:50:05 +02006447{
6448 int i, cur_len;
6449 u8 max_len;
6450
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006451 max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
Szymon Janc2bb368702016-09-18 12:50:05 +02006452
Arman Uguray4117ed72015-03-23 15:57:14 -07006453 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006454 return false;
6455
Arman Uguray4117ed72015-03-23 15:57:14 -07006456 /* Make sure that the data is correctly formatted. */
6457 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6458 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006459
Szymon Janc9c9db782016-09-18 12:50:06 +02006460 if (data[i + 1] == EIR_FLAGS &&
6461 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006462 return false;
6463
Szymon Janc2bb368702016-09-18 12:50:05 +02006464 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6465 return false;
6466
6467 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6468 return false;
6469
6470 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6471 return false;
6472
6473 if (data[i + 1] == EIR_APPEARANCE &&
6474 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006475 return false;
6476
Arman Uguray24b4f382015-03-23 15:57:12 -07006477 /* If the current field length would exceed the total data
6478 * length, then it's invalid.
6479 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006480 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006481 return false;
6482 }
6483
6484 return true;
6485}
6486
Arman Uguray24b4f382015-03-23 15:57:12 -07006487static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6488 u16 opcode)
6489{
6490 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006491 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006492 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006493 struct adv_info *adv_instance, *n;
6494 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006495
6496 BT_DBG("status %d", status);
6497
6498 hci_dev_lock(hdev);
6499
6500 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6501
Florian Grandelfffd38b2015-06-18 03:16:47 +02006502 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6503 if (!adv_instance->pending)
6504 continue;
6505
6506 if (!status) {
6507 adv_instance->pending = false;
6508 continue;
6509 }
6510
6511 instance = adv_instance->instance;
6512
6513 if (hdev->cur_adv_instance == instance)
6514 cancel_adv_timeout(hdev);
6515
6516 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006517 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006518 }
6519
6520 if (!cmd)
6521 goto unlock;
6522
Florian Grandelfffd38b2015-06-18 03:16:47 +02006523 cp = cmd->param;
6524 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006525
6526 if (status)
6527 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6528 mgmt_status(status));
6529 else
6530 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6531 mgmt_status(status), &rp, sizeof(rp));
6532
6533 mgmt_pending_remove(cmd);
6534
6535unlock:
6536 hci_dev_unlock(hdev);
6537}
6538
6539static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6540 void *data, u16 data_len)
6541{
6542 struct mgmt_cp_add_advertising *cp = data;
6543 struct mgmt_rp_add_advertising rp;
6544 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006545 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006546 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006547 u16 timeout, duration;
6548 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6549 u8 schedule_instance = 0;
6550 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006551 int err;
6552 struct mgmt_pending_cmd *cmd;
6553 struct hci_request req;
6554
6555 BT_DBG("%s", hdev->name);
6556
6557 status = mgmt_le_support(hdev);
6558 if (status)
6559 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6560 status);
6561
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006562 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6563 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6564 MGMT_STATUS_INVALID_PARAMS);
6565
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006566 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6567 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6568 MGMT_STATUS_INVALID_PARAMS);
6569
Arman Uguray24b4f382015-03-23 15:57:12 -07006570 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006571 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006572 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006573
Florian Grandelfffd38b2015-06-18 03:16:47 +02006574 /* The current implementation only supports a subset of the specified
6575 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006576 */
6577 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006578 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006579 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6580 MGMT_STATUS_INVALID_PARAMS);
6581
6582 hci_dev_lock(hdev);
6583
Arman Uguray912098a2015-03-23 15:57:15 -07006584 if (timeout && !hdev_is_powered(hdev)) {
6585 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6586 MGMT_STATUS_REJECTED);
6587 goto unlock;
6588 }
6589
Arman Uguray24b4f382015-03-23 15:57:12 -07006590 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006591 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006592 pending_find(MGMT_OP_SET_LE, hdev)) {
6593 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6594 MGMT_STATUS_BUSY);
6595 goto unlock;
6596 }
6597
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006598 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
6599 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006600 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006601 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6602 MGMT_STATUS_INVALID_PARAMS);
6603 goto unlock;
6604 }
6605
Florian Grandelfffd38b2015-06-18 03:16:47 +02006606 err = hci_add_adv_instance(hdev, cp->instance, flags,
6607 cp->adv_data_len, cp->data,
6608 cp->scan_rsp_len,
6609 cp->data + cp->adv_data_len,
6610 timeout, duration);
6611 if (err < 0) {
6612 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6613 MGMT_STATUS_FAILED);
6614 goto unlock;
6615 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006616
Florian Grandelfffd38b2015-06-18 03:16:47 +02006617 /* Only trigger an advertising added event if a new instance was
6618 * actually added.
6619 */
6620 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006621 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006622
Florian Grandelfffd38b2015-06-18 03:16:47 +02006623 if (hdev->cur_adv_instance == cp->instance) {
6624 /* If the currently advertised instance is being changed then
6625 * cancel the current advertising and schedule the next
6626 * instance. If there is only one instance then the overridden
6627 * advertising data will be visible right away.
6628 */
6629 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006630
Florian Grandelfffd38b2015-06-18 03:16:47 +02006631 next_instance = hci_get_next_instance(hdev, cp->instance);
6632 if (next_instance)
6633 schedule_instance = next_instance->instance;
6634 } else if (!hdev->adv_instance_timeout) {
6635 /* Immediately advertise the new instance if no other
6636 * instance is currently being advertised.
6637 */
6638 schedule_instance = cp->instance;
6639 }
Arman Uguray912098a2015-03-23 15:57:15 -07006640
Florian Grandelfffd38b2015-06-18 03:16:47 +02006641 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6642 * there is no instance to be advertised then we have no HCI
6643 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006644 */
6645 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006646 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6647 !schedule_instance) {
6648 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006649 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6650 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6651 goto unlock;
6652 }
6653
6654 /* We're good to go, update advertising data, parameters, and start
6655 * advertising.
6656 */
6657 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6658 data_len);
6659 if (!cmd) {
6660 err = -ENOMEM;
6661 goto unlock;
6662 }
6663
6664 hci_req_init(&req, hdev);
6665
Johan Hedbergf2252572015-11-18 12:49:20 +02006666 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006667
Florian Grandelfffd38b2015-06-18 03:16:47 +02006668 if (!err)
6669 err = hci_req_run(&req, add_advertising_complete);
6670
Arman Uguray24b4f382015-03-23 15:57:12 -07006671 if (err < 0)
6672 mgmt_pending_remove(cmd);
6673
6674unlock:
6675 hci_dev_unlock(hdev);
6676
6677 return err;
6678}
6679
Arman Ugurayda9293352015-03-23 15:57:13 -07006680static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6681 u16 opcode)
6682{
6683 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006684 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006685 struct mgmt_rp_remove_advertising rp;
6686
6687 BT_DBG("status %d", status);
6688
6689 hci_dev_lock(hdev);
6690
6691 /* A failure status here only means that we failed to disable
6692 * advertising. Otherwise, the advertising instance has been removed,
6693 * so report success.
6694 */
6695 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6696 if (!cmd)
6697 goto unlock;
6698
Florian Grandel01948332015-06-18 03:16:48 +02006699 cp = cmd->param;
6700 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006701
6702 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6703 &rp, sizeof(rp));
6704 mgmt_pending_remove(cmd);
6705
6706unlock:
6707 hci_dev_unlock(hdev);
6708}
6709
6710static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6711 void *data, u16 data_len)
6712{
6713 struct mgmt_cp_remove_advertising *cp = data;
6714 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006715 struct mgmt_pending_cmd *cmd;
6716 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006717 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006718
6719 BT_DBG("%s", hdev->name);
6720
Arman Ugurayda9293352015-03-23 15:57:13 -07006721 hci_dev_lock(hdev);
6722
Johan Hedberg952497b2015-06-18 21:05:31 +03006723 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006724 err = mgmt_cmd_status(sk, hdev->id,
6725 MGMT_OP_REMOVE_ADVERTISING,
6726 MGMT_STATUS_INVALID_PARAMS);
6727 goto unlock;
6728 }
6729
Arman Ugurayda9293352015-03-23 15:57:13 -07006730 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6731 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6732 pending_find(MGMT_OP_SET_LE, hdev)) {
6733 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6734 MGMT_STATUS_BUSY);
6735 goto unlock;
6736 }
6737
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006738 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006739 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6740 MGMT_STATUS_INVALID_PARAMS);
6741 goto unlock;
6742 }
6743
Florian Grandel01948332015-06-18 03:16:48 +02006744 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006745
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006746 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006747
Florian Grandel01948332015-06-18 03:16:48 +02006748 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006749 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006750
Florian Grandel01948332015-06-18 03:16:48 +02006751 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6752 * flag is set or the device isn't powered then we have no HCI
6753 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006754 */
Florian Grandel01948332015-06-18 03:16:48 +02006755 if (skb_queue_empty(&req.cmd_q) ||
6756 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006757 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Jaganath Kanakkasseryf17d8582017-10-25 10:58:48 +05306758 hci_req_purge(&req);
Florian Grandel01948332015-06-18 03:16:48 +02006759 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006760 err = mgmt_cmd_complete(sk, hdev->id,
6761 MGMT_OP_REMOVE_ADVERTISING,
6762 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6763 goto unlock;
6764 }
6765
6766 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6767 data_len);
6768 if (!cmd) {
6769 err = -ENOMEM;
6770 goto unlock;
6771 }
6772
Arman Ugurayda9293352015-03-23 15:57:13 -07006773 err = hci_req_run(&req, remove_advertising_complete);
6774 if (err < 0)
6775 mgmt_pending_remove(cmd);
6776
6777unlock:
6778 hci_dev_unlock(hdev);
6779
6780 return err;
6781}
6782
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006783static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6784 void *data, u16 data_len)
6785{
6786 struct mgmt_cp_get_adv_size_info *cp = data;
6787 struct mgmt_rp_get_adv_size_info rp;
6788 u32 flags, supported_flags;
6789 int err;
6790
6791 BT_DBG("%s", hdev->name);
6792
6793 if (!lmp_le_capable(hdev))
6794 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6795 MGMT_STATUS_REJECTED);
6796
6797 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6799 MGMT_STATUS_INVALID_PARAMS);
6800
6801 flags = __le32_to_cpu(cp->flags);
6802
6803 /* The current implementation only supports a subset of the specified
6804 * flags.
6805 */
6806 supported_flags = get_supported_adv_flags(hdev);
6807 if (flags & ~supported_flags)
6808 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6809 MGMT_STATUS_INVALID_PARAMS);
6810
6811 rp.instance = cp->instance;
6812 rp.flags = cp->flags;
MichaƂ Narajowskif61851f2016-10-19 10:20:27 +02006813 rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
6814 rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006815
6816 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6817 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6818
6819 return err;
6820}
6821
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006822static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006823 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006824 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006825 HCI_MGMT_NO_HDEV |
6826 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006827 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006828 HCI_MGMT_NO_HDEV |
6829 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006830 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006831 HCI_MGMT_NO_HDEV |
6832 HCI_MGMT_UNTRUSTED },
6833 { read_controller_info, MGMT_READ_INFO_SIZE,
6834 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006835 { set_powered, MGMT_SETTING_SIZE },
6836 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6837 { set_connectable, MGMT_SETTING_SIZE },
6838 { set_fast_connectable, MGMT_SETTING_SIZE },
6839 { set_bondable, MGMT_SETTING_SIZE },
6840 { set_link_security, MGMT_SETTING_SIZE },
6841 { set_ssp, MGMT_SETTING_SIZE },
6842 { set_hs, MGMT_SETTING_SIZE },
6843 { set_le, MGMT_SETTING_SIZE },
6844 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6845 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6846 { add_uuid, MGMT_ADD_UUID_SIZE },
6847 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006848 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6849 HCI_MGMT_VAR_LEN },
6850 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6851 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006852 { disconnect, MGMT_DISCONNECT_SIZE },
6853 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6854 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6855 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6856 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6857 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6858 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6859 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6860 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6861 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6862 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6863 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006864 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6865 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6866 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006867 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6868 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6869 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6870 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6871 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6872 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6873 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6874 { set_advertising, MGMT_SETTING_SIZE },
6875 { set_bredr, MGMT_SETTING_SIZE },
6876 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6877 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6878 { set_secure_conn, MGMT_SETTING_SIZE },
6879 { set_debug_keys, MGMT_SETTING_SIZE },
6880 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006881 { load_irks, MGMT_LOAD_IRKS_SIZE,
6882 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006883 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6884 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6885 { add_device, MGMT_ADD_DEVICE_SIZE },
6886 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006887 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6888 HCI_MGMT_VAR_LEN },
6889 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006890 HCI_MGMT_NO_HDEV |
6891 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006892 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006893 HCI_MGMT_UNCONFIGURED |
6894 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006895 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6896 HCI_MGMT_UNCONFIGURED },
6897 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6898 HCI_MGMT_UNCONFIGURED },
6899 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6900 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006901 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006902 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006903 HCI_MGMT_NO_HDEV |
6904 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006905 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006906 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6907 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006908 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006909 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006910 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006911 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6912 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006913 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Jaganath Kanakkassery62446912018-07-19 17:09:34 +05306914 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
Jaganath Kanakkassery0314f282018-07-19 17:09:35 +05306915 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006916};
6917
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006918void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006919{
Marcel Holtmannced85542015-03-14 19:27:56 -07006920 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006921
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006922 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6923 return;
6924
Marcel Holtmannf9207332015-03-14 19:27:55 -07006925 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006926 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006927 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6928 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6929 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006930 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006931 } else {
6932 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6933 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006934 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006935 }
6936 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006937 case HCI_AMP:
6938 ev.type = 0x02;
6939 break;
6940 default:
6941 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006942 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006943
6944 ev.bus = hdev->bus;
6945
6946 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6947 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006948}
6949
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006950void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006951{
Marcel Holtmannced85542015-03-14 19:27:56 -07006952 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006953 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006954
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006955 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6956 return;
6957
Marcel Holtmannf9207332015-03-14 19:27:55 -07006958 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006959 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006960 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006961
Marcel Holtmannf9207332015-03-14 19:27:55 -07006962 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6963 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6964 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006965 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006966 } else {
6967 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6968 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006969 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006970 }
6971 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006972 case HCI_AMP:
6973 ev.type = 0x02;
6974 break;
6975 default:
6976 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006977 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006978
6979 ev.bus = hdev->bus;
6980
6981 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6982 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006983}
6984
Andre Guedes6046dc32014-02-26 20:21:51 -03006985/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006986static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006987{
6988 struct hci_conn_params *p;
6989
6990 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006991 /* Needed for AUTO_OFF case where might not "really"
6992 * have been powered off.
6993 */
6994 list_del_init(&p->action);
6995
6996 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006997 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006998 case HCI_AUTO_CONN_ALWAYS:
6999 list_add(&p->action, &hdev->pend_le_conns);
7000 break;
7001 case HCI_AUTO_CONN_REPORT:
7002 list_add(&p->action, &hdev->pend_le_reports);
7003 break;
7004 default:
7005 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007006 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007007 }
7008}
7009
Johan Hedberg2ff13892015-11-25 16:15:44 +02007010void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05007011{
7012 struct cmd_lookup match = { NULL, hdev };
7013
Johan Hedberg2ff13892015-11-25 16:15:44 +02007014 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05007015
Johan Hedberg2ff13892015-11-25 16:15:44 +02007016 hci_dev_lock(hdev);
7017
7018 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02007019 restart_le_actions(hdev);
7020 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007021 }
7022
Johan Hedberg229ab392013-03-15 17:06:53 -05007023 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7024
7025 new_settings(hdev, match.sk);
7026
Johan Hedberg229ab392013-03-15 17:06:53 -05007027 if (match.sk)
7028 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02007029
7030 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05007031}
7032
Johan Hedberg2ff13892015-11-25 16:15:44 +02007033void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007034{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007035 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007036 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02007037
Johan Hedberg229ab392013-03-15 17:06:53 -05007038 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007039
7040 /* If the power off is because of hdev unregistration let
7041 * use the appropriate INVALID_INDEX status. Otherwise use
7042 * NOT_POWERED. We cover both scenarios here since later in
7043 * mgmt_index_removed() any hci_conn callbacks will have already
7044 * been triggered, potentially causing misleading DISCONNECTED
7045 * status responses.
7046 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007047 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007048 status = MGMT_STATUS_INVALID_INDEX;
7049 else
7050 status = MGMT_STATUS_NOT_POWERED;
7051
7052 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007053
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007054 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007055 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7056 zero_cod, sizeof(zero_cod),
7057 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007058 ext_info_changed(hdev, NULL);
7059 }
Johan Hedberg229ab392013-03-15 17:06:53 -05007060
Johan Hedberg2ff13892015-11-25 16:15:44 +02007061 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007062
7063 if (match.sk)
7064 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02007065}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007066
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007067void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007068{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007069 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007070 u8 status;
7071
Johan Hedberg333ae952015-03-17 13:48:47 +02007072 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007073 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007074 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007075
7076 if (err == -ERFKILL)
7077 status = MGMT_STATUS_RFKILLED;
7078 else
7079 status = MGMT_STATUS_FAILED;
7080
Johan Hedberga69e8372015-03-06 21:08:53 +02007081 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007082
7083 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007084}
7085
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007086void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7087 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007088{
Johan Hedberg86742e12011-11-07 23:13:38 +02007089 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007090
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007091 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007092
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007093 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007094 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007095 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007096 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007097 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007098 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007099
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007100 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007101}
Johan Hedbergf7520542011-01-20 12:34:39 +02007102
Johan Hedbergd7b25452014-05-23 13:19:53 +03007103static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7104{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007105 switch (ltk->type) {
7106 case SMP_LTK:
7107 case SMP_LTK_SLAVE:
7108 if (ltk->authenticated)
7109 return MGMT_LTK_AUTHENTICATED;
7110 return MGMT_LTK_UNAUTHENTICATED;
7111 case SMP_LTK_P256:
7112 if (ltk->authenticated)
7113 return MGMT_LTK_P256_AUTH;
7114 return MGMT_LTK_P256_UNAUTH;
7115 case SMP_LTK_P256_DEBUG:
7116 return MGMT_LTK_P256_DEBUG;
7117 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007118
7119 return MGMT_LTK_UNAUTHENTICATED;
7120}
7121
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007122void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007123{
7124 struct mgmt_ev_new_long_term_key ev;
7125
7126 memset(&ev, 0, sizeof(ev));
7127
Marcel Holtmann5192d302014-02-19 17:11:58 -08007128 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007129 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007130 * to store long term keys. Their addresses will change the
7131 * next time around.
7132 *
7133 * Only when a remote device provides an identity address
7134 * make sure the long term key is stored. If the remote
7135 * identity is known, the long term keys are internally
7136 * mapped to the identity address. So allow static random
7137 * and public addresses here.
7138 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007139 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7140 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7141 ev.store_hint = 0x00;
7142 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007143 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007144
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007145 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007146 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007147 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007148 ev.key.enc_size = key->enc_size;
7149 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007150 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007151
Johan Hedberg2ceba532014-06-16 19:25:16 +03007152 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007153 ev.key.master = 1;
7154
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007155 /* Make sure we copy only the significant bytes based on the
7156 * encryption key size, and set the rest of the value to zeroes.
7157 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007158 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007159 memset(ev.key.val + key->enc_size, 0,
7160 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007161
Marcel Holtmann083368f2013-10-15 14:26:29 -07007162 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007163}
7164
Johan Hedbergcad20c22015-10-12 13:36:19 +02007165void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007166{
7167 struct mgmt_ev_new_irk ev;
7168
7169 memset(&ev, 0, sizeof(ev));
7170
Johan Hedbergcad20c22015-10-12 13:36:19 +02007171 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007172
Johan Hedberg95fbac82014-02-19 15:18:31 +02007173 bacpy(&ev.rpa, &irk->rpa);
7174 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7175 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7176 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7177
7178 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7179}
7180
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007181void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7182 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007183{
7184 struct mgmt_ev_new_csrk ev;
7185
7186 memset(&ev, 0, sizeof(ev));
7187
7188 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007189 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007190 * to store signature resolving keys. Their addresses will change
7191 * the next time around.
7192 *
7193 * Only when a remote device provides an identity address
7194 * make sure the signature resolving key is stored. So allow
7195 * static random and public addresses here.
7196 */
7197 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7198 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7199 ev.store_hint = 0x00;
7200 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007201 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007202
7203 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7204 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007205 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007206 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7207
7208 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7209}
7210
Andre Guedesffb5a8272014-07-01 18:10:11 -03007211void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007212 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7213 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007214{
7215 struct mgmt_ev_new_conn_param ev;
7216
Johan Hedbergc103aea2014-07-02 17:37:34 +03007217 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7218 return;
7219
Andre Guedesffb5a8272014-07-01 18:10:11 -03007220 memset(&ev, 0, sizeof(ev));
7221 bacpy(&ev.addr.bdaddr, bdaddr);
7222 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007223 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007224 ev.min_interval = cpu_to_le16(min_interval);
7225 ev.max_interval = cpu_to_le16(max_interval);
7226 ev.latency = cpu_to_le16(latency);
7227 ev.timeout = cpu_to_le16(timeout);
7228
7229 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7230}
7231
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007232void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7233 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007234{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007235 char buf[512];
7236 struct mgmt_ev_device_connected *ev = (void *) buf;
7237 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007238
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007239 bacpy(&ev->addr.bdaddr, &conn->dst);
7240 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007241
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007242 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007243
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007244 /* We must ensure that the EIR Data fields are ordered and
7245 * unique. Keep it simple for now and avoid the problem by not
7246 * adding any BR/EDR data to the LE adv.
7247 */
7248 if (conn->le_adv_data_len > 0) {
7249 memcpy(&ev->eir[eir_len],
7250 conn->le_adv_data, conn->le_adv_data_len);
7251 eir_len = conn->le_adv_data_len;
7252 } else {
7253 if (name_len > 0)
7254 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7255 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007256
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007257 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007258 eir_len = eir_append_data(ev->eir, eir_len,
7259 EIR_CLASS_OF_DEV,
7260 conn->dev_class, 3);
7261 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007262
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007263 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007264
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007265 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7266 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007267}
7268
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007269static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007270{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007271 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007272
Johan Hedbergf5818c22014-12-05 13:36:02 +02007273 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007274
7275 *sk = cmd->sk;
7276 sock_hold(*sk);
7277
Johan Hedberga664b5b2011-02-19 12:06:02 -03007278 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007279}
7280
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007281static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007282{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007283 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007284 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007285
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007286 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7287
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007288 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007289 mgmt_pending_remove(cmd);
7290}
7291
Johan Hedberg84c61d92014-08-01 11:13:30 +03007292bool mgmt_powering_down(struct hci_dev *hdev)
7293{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007294 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007295 struct mgmt_mode *cp;
7296
Johan Hedberg333ae952015-03-17 13:48:47 +02007297 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007298 if (!cmd)
7299 return false;
7300
7301 cp = cmd->param;
7302 if (!cp->val)
7303 return true;
7304
7305 return false;
7306}
7307
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007308void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007309 u8 link_type, u8 addr_type, u8 reason,
7310 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007311{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007312 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007313 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007314
Johan Hedberg84c61d92014-08-01 11:13:30 +03007315 /* The connection is still in hci_conn_hash so test for 1
7316 * instead of 0 to know if this is the last one.
7317 */
7318 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7319 cancel_delayed_work(&hdev->power_off);
7320 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007321 }
7322
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007323 if (!mgmt_connected)
7324 return;
7325
Andre Guedes57eb7762013-10-30 19:01:41 -03007326 if (link_type != ACL_LINK && link_type != LE_LINK)
7327 return;
7328
Johan Hedberg744cf192011-11-08 20:40:14 +02007329 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007330
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007331 bacpy(&ev.addr.bdaddr, bdaddr);
7332 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7333 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007334
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007335 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007336
7337 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007338 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007339
Johan Hedberg124f6e32012-02-09 13:50:12 +02007340 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007341 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007342}
7343
Marcel Holtmann78929242013-10-06 23:55:47 -07007344void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7345 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007346{
Andre Guedes3655bba2013-10-30 19:01:40 -03007347 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7348 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007349 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007350
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007351 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7352 hdev);
7353
Johan Hedberg333ae952015-03-17 13:48:47 +02007354 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007355 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007356 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007357
Andre Guedes3655bba2013-10-30 19:01:40 -03007358 cp = cmd->param;
7359
7360 if (bacmp(bdaddr, &cp->addr.bdaddr))
7361 return;
7362
7363 if (cp->addr.type != bdaddr_type)
7364 return;
7365
Johan Hedbergf5818c22014-12-05 13:36:02 +02007366 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007367 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007368}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007369
Marcel Holtmann445608d2013-10-06 23:55:48 -07007370void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7371 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007372{
7373 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007374
Johan Hedberg84c61d92014-08-01 11:13:30 +03007375 /* The connection is still in hci_conn_hash so test for 1
7376 * instead of 0 to know if this is the last one.
7377 */
7378 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7379 cancel_delayed_work(&hdev->power_off);
7380 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007381 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007382
Johan Hedberg4c659c32011-11-07 23:13:39 +02007383 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007384 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007385 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007386
Marcel Holtmann445608d2013-10-06 23:55:48 -07007387 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007388}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007389
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007390void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007391{
7392 struct mgmt_ev_pin_code_request ev;
7393
Johan Hedbergd8457692012-02-17 14:24:57 +02007394 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007395 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007396 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007397
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007398 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007399}
7400
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007401void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7402 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007403{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007404 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007405
Johan Hedberg333ae952015-03-17 13:48:47 +02007406 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007407 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007408 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007409
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007410 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007411 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007412}
7413
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007414void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7415 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007416{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007417 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007418
Johan Hedberg333ae952015-03-17 13:48:47 +02007419 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007420 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007421 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007422
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007423 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007424 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007425}
Johan Hedberga5c29682011-02-19 12:05:57 -03007426
Johan Hedberg744cf192011-11-08 20:40:14 +02007427int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007428 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007429 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007430{
7431 struct mgmt_ev_user_confirm_request ev;
7432
Johan Hedberg744cf192011-11-08 20:40:14 +02007433 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007434
Johan Hedberg272d90d2012-02-09 15:26:12 +02007435 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007436 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007437 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007438 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007439
Johan Hedberg744cf192011-11-08 20:40:14 +02007440 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007441 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007442}
7443
Johan Hedberg272d90d2012-02-09 15:26:12 +02007444int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007445 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007446{
7447 struct mgmt_ev_user_passkey_request ev;
7448
7449 BT_DBG("%s", hdev->name);
7450
Johan Hedberg272d90d2012-02-09 15:26:12 +02007451 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007452 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007453
7454 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007455 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007456}
7457
Brian Gix0df4c182011-11-16 13:53:13 -08007458static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007459 u8 link_type, u8 addr_type, u8 status,
7460 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007461{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007462 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007463
Johan Hedberg333ae952015-03-17 13:48:47 +02007464 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007465 if (!cmd)
7466 return -ENOENT;
7467
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007468 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007469 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007470
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007471 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007472}
7473
Johan Hedberg744cf192011-11-08 20:40:14 +02007474int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007475 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007476{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007477 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007478 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007479}
7480
Johan Hedberg272d90d2012-02-09 15:26:12 +02007481int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007482 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007483{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007484 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007485 status,
7486 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007487}
Johan Hedberg2a611692011-02-19 12:06:00 -03007488
Brian Gix604086b2011-11-23 08:28:33 -08007489int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007490 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007491{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007492 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007493 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007494}
7495
Johan Hedberg272d90d2012-02-09 15:26:12 +02007496int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007497 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007498{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007499 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007500 status,
7501 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007502}
7503
Johan Hedberg92a25252012-09-06 18:39:26 +03007504int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7505 u8 link_type, u8 addr_type, u32 passkey,
7506 u8 entered)
7507{
7508 struct mgmt_ev_passkey_notify ev;
7509
7510 BT_DBG("%s", hdev->name);
7511
7512 bacpy(&ev.addr.bdaddr, bdaddr);
7513 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7514 ev.passkey = __cpu_to_le32(passkey);
7515 ev.entered = entered;
7516
7517 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7518}
7519
Johan Hedberge1e930f2014-09-08 17:09:49 -07007520void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007521{
7522 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007523 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007524 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007525
Johan Hedberge1e930f2014-09-08 17:09:49 -07007526 bacpy(&ev.addr.bdaddr, &conn->dst);
7527 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7528 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007529
Johan Hedberge1e930f2014-09-08 17:09:49 -07007530 cmd = find_pairing(conn);
7531
7532 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7533 cmd ? cmd->sk : NULL);
7534
Johan Hedberga511b352014-12-11 21:45:45 +02007535 if (cmd) {
7536 cmd->cmd_complete(cmd, status);
7537 mgmt_pending_remove(cmd);
7538 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007539}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007540
Marcel Holtmann464996a2013-10-15 14:26:24 -07007541void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007542{
7543 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007544 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007545
7546 if (status) {
7547 u8 mgmt_err = mgmt_status(status);
7548 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007549 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007550 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007551 }
7552
Marcel Holtmann464996a2013-10-15 14:26:24 -07007553 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007554 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007555 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007556 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007557
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007558 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007559 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007560
Johan Hedberg47990ea2012-02-22 11:58:37 +02007561 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007562 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007563
7564 if (match.sk)
7565 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007566}
7567
Johan Hedberg890ea892013-03-15 17:06:52 -05007568static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007569{
Johan Hedberg890ea892013-03-15 17:06:52 -05007570 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007571 struct hci_cp_write_eir cp;
7572
Johan Hedberg976eb202012-10-24 21:12:01 +03007573 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007574 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007575
Johan Hedbergc80da272012-02-22 15:38:48 +02007576 memset(hdev->eir, 0, sizeof(hdev->eir));
7577
Johan Hedbergcacaf522012-02-21 00:52:42 +02007578 memset(&cp, 0, sizeof(cp));
7579
Johan Hedberg890ea892013-03-15 17:06:52 -05007580 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007581}
7582
Marcel Holtmann3e248562013-10-15 14:26:25 -07007583void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007584{
7585 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007586 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007587 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007588
7589 if (status) {
7590 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007591
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007592 if (enable && hci_dev_test_and_clear_flag(hdev,
7593 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007594 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007595 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007596 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007597
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007598 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7599 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007600 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007601 }
7602
7603 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007604 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007605 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007606 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007607 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007608 changed = hci_dev_test_and_clear_flag(hdev,
7609 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007610 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007611 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007612 }
7613
7614 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7615
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007616 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007617 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007618
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007619 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007620 sock_put(match.sk);
7621
Johan Hedberg890ea892013-03-15 17:06:52 -05007622 hci_req_init(&req, hdev);
7623
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007624 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7625 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007626 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7627 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007628 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007629 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007630 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007631 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007632
7633 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007634}
7635
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007636static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007637{
7638 struct cmd_lookup *match = data;
7639
Johan Hedberg90e70452012-02-23 23:09:40 +02007640 if (match->sk == NULL) {
7641 match->sk = cmd->sk;
7642 sock_hold(match->sk);
7643 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007644}
7645
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007646void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7647 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007648{
Johan Hedberg90e70452012-02-23 23:09:40 +02007649 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007650
Johan Hedberg92da6092013-03-15 17:06:55 -05007651 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7652 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7653 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007654
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007655 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007656 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7657 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007658 ext_info_changed(hdev, NULL);
7659 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007660
7661 if (match.sk)
7662 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007663}
7664
Marcel Holtmann7667da32013-10-15 14:26:27 -07007665void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007666{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007667 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007668 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007669
Johan Hedberg13928972013-03-15 17:07:00 -05007670 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007671 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007672
7673 memset(&ev, 0, sizeof(ev));
7674 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007675 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007676
Johan Hedberg333ae952015-03-17 13:48:47 +02007677 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007678 if (!cmd) {
7679 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007680
Johan Hedberg13928972013-03-15 17:07:00 -05007681 /* If this is a HCI command related to powering on the
7682 * HCI dev don't send any mgmt signals.
7683 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007684 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007685 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007686 }
7687
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007688 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7689 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007690 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007691}
Szymon Jancc35938b2011-03-22 13:12:21 +01007692
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007693static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7694{
7695 int i;
7696
7697 for (i = 0; i < uuid_count; i++) {
7698 if (!memcmp(uuid, uuids[i], 16))
7699 return true;
7700 }
7701
7702 return false;
7703}
7704
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007705static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7706{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007707 u16 parsed = 0;
7708
7709 while (parsed < eir_len) {
7710 u8 field_len = eir[0];
7711 u8 uuid[16];
7712 int i;
7713
7714 if (field_len == 0)
7715 break;
7716
7717 if (eir_len - parsed < field_len + 1)
7718 break;
7719
7720 switch (eir[1]) {
7721 case EIR_UUID16_ALL:
7722 case EIR_UUID16_SOME:
7723 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007724 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007725 uuid[13] = eir[i + 3];
7726 uuid[12] = eir[i + 2];
7727 if (has_uuid(uuid, uuid_count, uuids))
7728 return true;
7729 }
7730 break;
7731 case EIR_UUID32_ALL:
7732 case EIR_UUID32_SOME:
7733 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007734 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007735 uuid[15] = eir[i + 5];
7736 uuid[14] = eir[i + 4];
7737 uuid[13] = eir[i + 3];
7738 uuid[12] = eir[i + 2];
7739 if (has_uuid(uuid, uuid_count, uuids))
7740 return true;
7741 }
7742 break;
7743 case EIR_UUID128_ALL:
7744 case EIR_UUID128_SOME:
7745 for (i = 0; i + 17 <= field_len; i += 16) {
7746 memcpy(uuid, eir + i + 2, 16);
7747 if (has_uuid(uuid, uuid_count, uuids))
7748 return true;
7749 }
7750 break;
7751 }
7752
7753 parsed += field_len + 1;
7754 eir += field_len + 1;
7755 }
7756
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007757 return false;
7758}
7759
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007760static void restart_le_scan(struct hci_dev *hdev)
7761{
7762 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007763 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007764 return;
7765
7766 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7767 hdev->discovery.scan_start +
7768 hdev->discovery.scan_duration))
7769 return;
7770
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007771 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007772 DISCOV_LE_RESTART_DELAY);
7773}
7774
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007775static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7776 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7777{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007778 /* If a RSSI threshold has been specified, and
7779 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7780 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7781 * is set, let it through for further processing, as we might need to
7782 * restart the scan.
7783 *
7784 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7785 * the results are also dropped.
7786 */
7787 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7788 (rssi == HCI_RSSI_INVALID ||
7789 (rssi < hdev->discovery.rssi &&
7790 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7791 return false;
7792
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007793 if (hdev->discovery.uuid_count != 0) {
7794 /* If a list of UUIDs is provided in filter, results with no
7795 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007796 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007797 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7798 hdev->discovery.uuids) &&
7799 !eir_has_uuids(scan_rsp, scan_rsp_len,
7800 hdev->discovery.uuid_count,
7801 hdev->discovery.uuids))
7802 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007803 }
7804
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007805 /* If duplicate filtering does not report RSSI changes, then restart
7806 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007807 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007808 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7809 restart_le_scan(hdev);
7810
7811 /* Validate RSSI value against the RSSI threshold once more. */
7812 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7813 rssi < hdev->discovery.rssi)
7814 return false;
7815 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007816
7817 return true;
7818}
7819
Marcel Holtmann901801b2013-10-06 23:55:51 -07007820void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007821 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7822 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007823{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007824 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007825 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007826 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007827
Johan Hedberg75ce2082014-07-02 22:42:01 +03007828 /* Don't send events for a non-kernel initiated discovery. With
7829 * LE one exception is if we have pend_le_reports > 0 in which
7830 * case we're doing passive scanning and want these events.
7831 */
7832 if (!hci_discovery_active(hdev)) {
7833 if (link_type == ACL_LINK)
7834 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007835 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007836 return;
7837 }
Andre Guedes12602d02013-04-30 15:29:40 -03007838
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007839 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007840 /* We are using service discovery */
7841 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7842 scan_rsp_len))
7843 return;
7844 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007845
Johan Hedberg78b781c2016-01-05 13:19:32 +02007846 if (hdev->discovery.limited) {
7847 /* Check for limited discoverable bit */
7848 if (dev_class) {
7849 if (!(dev_class[1] & 0x20))
7850 return;
7851 } else {
7852 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7853 if (!flags || !(flags[0] & LE_AD_LIMITED))
7854 return;
7855 }
7856 }
7857
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007858 /* Make sure that the buffer is big enough. The 5 extra bytes
7859 * are for the potential CoD field.
7860 */
7861 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007862 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007863
Johan Hedberg1dc06092012-01-15 21:01:23 +02007864 memset(buf, 0, sizeof(buf));
7865
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007866 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7867 * RSSI value was reported as 0 when not available. This behavior
7868 * is kept when using device discovery. This is required for full
7869 * backwards compatibility with the API.
7870 *
7871 * However when using service discovery, the value 127 will be
7872 * returned when the RSSI is not available.
7873 */
Szymon Janc91200e92015-01-22 16:57:05 +01007874 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7875 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007876 rssi = 0;
7877
Johan Hedberg841c5642014-07-07 12:45:54 +03007878 bacpy(&ev->addr.bdaddr, bdaddr);
7879 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007880 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007881 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007882
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007883 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007884 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007885 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007886
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007887 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7888 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007889 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007890 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007891
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007892 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007893 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007894 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007895
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007896 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7897 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007898
Marcel Holtmann901801b2013-10-06 23:55:51 -07007899 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007900}
Johan Hedberga88a9652011-03-30 13:18:12 +03007901
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007902void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7903 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007904{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007905 struct mgmt_ev_device_found *ev;
7906 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7907 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007908
Johan Hedbergb644ba32012-01-17 21:48:47 +02007909 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007910
Johan Hedbergb644ba32012-01-17 21:48:47 +02007911 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007912
Johan Hedbergb644ba32012-01-17 21:48:47 +02007913 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007914 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007915 ev->rssi = rssi;
7916
7917 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007918 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007919
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007920 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007921
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007922 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007923}
Johan Hedberg314b2382011-04-27 10:29:57 -04007924
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007925void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007926{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007927 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007928
Andre Guedes343fb142011-11-22 17:14:19 -03007929 BT_DBG("%s discovering %u", hdev->name, discovering);
7930
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007931 memset(&ev, 0, sizeof(ev));
7932 ev.type = hdev->discovery.type;
7933 ev.discovering = discovering;
7934
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007935 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007936}
Antti Julku5e762442011-08-25 16:48:02 +03007937
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007938static struct hci_mgmt_chan chan = {
7939 .channel = HCI_CHANNEL_CONTROL,
7940 .handler_count = ARRAY_SIZE(mgmt_handlers),
7941 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007942 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007943};
7944
7945int mgmt_init(void)
7946{
7947 return hci_mgmt_chan_register(&chan);
7948}
7949
7950void mgmt_exit(void)
7951{
7952 hci_mgmt_chan_unregister(&chan);
7953}