blob: d3837e0633afb1b3a0cd969dc6eae4cf094daa3f [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Szymon Janc33102302016-09-18 12:50:07 +020041#define MGMT_REVISION 14
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200106 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200107 MGMT_OP_READ_EXT_INFO,
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +0200108 MGMT_OP_SET_APPEARANCE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200109};
110
111static const u16 mgmt_events[] = {
112 MGMT_EV_CONTROLLER_ERROR,
113 MGMT_EV_INDEX_ADDED,
114 MGMT_EV_INDEX_REMOVED,
115 MGMT_EV_NEW_SETTINGS,
116 MGMT_EV_CLASS_OF_DEV_CHANGED,
117 MGMT_EV_LOCAL_NAME_CHANGED,
118 MGMT_EV_NEW_LINK_KEY,
119 MGMT_EV_NEW_LONG_TERM_KEY,
120 MGMT_EV_DEVICE_CONNECTED,
121 MGMT_EV_DEVICE_DISCONNECTED,
122 MGMT_EV_CONNECT_FAILED,
123 MGMT_EV_PIN_CODE_REQUEST,
124 MGMT_EV_USER_CONFIRM_REQUEST,
125 MGMT_EV_USER_PASSKEY_REQUEST,
126 MGMT_EV_AUTH_FAILED,
127 MGMT_EV_DEVICE_FOUND,
128 MGMT_EV_DISCOVERING,
129 MGMT_EV_DEVICE_BLOCKED,
130 MGMT_EV_DEVICE_UNBLOCKED,
131 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300132 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800133 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700134 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200135 MGMT_EV_DEVICE_ADDED,
136 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300137 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200138 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200139 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200140 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700141 MGMT_EV_EXT_INDEX_ADDED,
142 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700143 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700144 MGMT_EV_ADVERTISING_ADDED,
145 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200146 MGMT_EV_EXT_INFO_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200147};
148
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700149static const u16 mgmt_untrusted_commands[] = {
150 MGMT_OP_READ_INDEX_LIST,
151 MGMT_OP_READ_INFO,
152 MGMT_OP_READ_UNCONF_INDEX_LIST,
153 MGMT_OP_READ_CONFIG_INFO,
154 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200155 MGMT_OP_READ_EXT_INFO,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700156};
157
158static const u16 mgmt_untrusted_events[] = {
159 MGMT_EV_INDEX_ADDED,
160 MGMT_EV_INDEX_REMOVED,
161 MGMT_EV_NEW_SETTINGS,
162 MGMT_EV_CLASS_OF_DEV_CHANGED,
163 MGMT_EV_LOCAL_NAME_CHANGED,
164 MGMT_EV_UNCONF_INDEX_ADDED,
165 MGMT_EV_UNCONF_INDEX_REMOVED,
166 MGMT_EV_NEW_CONFIG_OPTIONS,
167 MGMT_EV_EXT_INDEX_ADDED,
168 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200169 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700170};
171
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800172#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200173
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200174#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
175 "\x00\x00\x00\x00\x00\x00\x00\x00"
176
Johan Hedbergca69b792011-11-11 18:10:00 +0200177/* HCI to MGMT error code conversion table */
178static u8 mgmt_status_table[] = {
179 MGMT_STATUS_SUCCESS,
180 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
181 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
182 MGMT_STATUS_FAILED, /* Hardware Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
184 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200185 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200186 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
187 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
188 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
189 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
190 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
191 MGMT_STATUS_BUSY, /* Command Disallowed */
192 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
193 MGMT_STATUS_REJECTED, /* Rejected Security */
194 MGMT_STATUS_REJECTED, /* Rejected Personal */
195 MGMT_STATUS_TIMEOUT, /* Host Timeout */
196 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
197 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
198 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
199 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
200 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
201 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
202 MGMT_STATUS_BUSY, /* Repeated Attempts */
203 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
204 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
206 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
207 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
208 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
209 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
210 MGMT_STATUS_FAILED, /* Unspecified Error */
211 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
212 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
213 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
214 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
215 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
216 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
217 MGMT_STATUS_FAILED, /* Unit Link Key Used */
218 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
219 MGMT_STATUS_TIMEOUT, /* Instant Passed */
220 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
221 MGMT_STATUS_FAILED, /* Transaction Collision */
222 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
223 MGMT_STATUS_REJECTED, /* QoS Rejected */
224 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
225 MGMT_STATUS_REJECTED, /* Insufficient Security */
226 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
227 MGMT_STATUS_BUSY, /* Role Switch Pending */
228 MGMT_STATUS_FAILED, /* Slot Violation */
229 MGMT_STATUS_FAILED, /* Role Switch Failed */
230 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
231 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
232 MGMT_STATUS_BUSY, /* Host Busy Pairing */
233 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
234 MGMT_STATUS_BUSY, /* Controller Busy */
235 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
236 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
237 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
238 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
239 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
240};
241
242static u8 mgmt_status(u8 hci_status)
243{
244 if (hci_status < ARRAY_SIZE(mgmt_status_table))
245 return mgmt_status_table[hci_status];
246
247 return MGMT_STATUS_FAILED;
248}
249
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700250static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
251 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700252{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700253 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
254 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700255}
256
Marcel Holtmann72000df2015-03-16 16:11:21 -0700257static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
258 u16 len, int flag, struct sock *skip_sk)
259{
260 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
261 flag, skip_sk);
262}
263
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200264static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
265 struct sock *skip_sk)
266{
267 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700268 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200269}
270
Johan Hedberg85813a72015-10-21 18:02:59 +0300271static u8 le_addr_type(u8 mgmt_addr_type)
272{
273 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
274 return ADDR_LE_DEV_PUBLIC;
275 else
276 return ADDR_LE_DEV_RANDOM;
277}
278
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200279void mgmt_fill_version_info(void *ver)
280{
281 struct mgmt_rp_read_version *rp = ver;
282
283 rp->version = MGMT_VERSION;
284 rp->revision = cpu_to_le16(MGMT_REVISION);
285}
286
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300287static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
288 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200289{
290 struct mgmt_rp_read_version rp;
291
292 BT_DBG("sock %p", sk);
293
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200294 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200295
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200296 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
297 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200298}
299
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300300static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
301 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302{
303 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305 size_t rp_size;
306 int i, err;
307
308 BT_DBG("sock %p", sk);
309
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700310 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
311 num_commands = ARRAY_SIZE(mgmt_commands);
312 num_events = ARRAY_SIZE(mgmt_events);
313 } else {
314 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
315 num_events = ARRAY_SIZE(mgmt_untrusted_events);
316 }
317
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200318 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
319
320 rp = kmalloc(rp_size, GFP_KERNEL);
321 if (!rp)
322 return -ENOMEM;
323
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700324 rp->num_commands = cpu_to_le16(num_commands);
325 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200326
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700327 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
328 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200329
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700330 for (i = 0; i < num_commands; i++, opcode++)
331 put_unaligned_le16(mgmt_commands[i], opcode);
332
333 for (i = 0; i < num_events; i++, opcode++)
334 put_unaligned_le16(mgmt_events[i], opcode);
335 } else {
336 __le16 *opcode = rp->opcodes;
337
338 for (i = 0; i < num_commands; i++, opcode++)
339 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
340
341 for (i = 0; i < num_events; i++, opcode++)
342 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
343 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200344
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200345 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
346 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200347 kfree(rp);
348
349 return err;
350}
351
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300352static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
353 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200356 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300359 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
361 BT_DBG("sock %p", sk);
362
363 read_lock(&hci_dev_list_lock);
364
365 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300366 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200367 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700368 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700369 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 }
371
Johan Hedberga38528f2011-01-22 06:46:43 +0200372 rp_len = sizeof(*rp) + (2 * count);
373 rp = kmalloc(rp_len, GFP_ATOMIC);
374 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100375 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200376 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100377 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200378
Johan Hedberg476e44c2012-10-19 20:10:46 +0300379 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200380 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700381 if (hci_dev_test_flag(d, HCI_SETUP) ||
382 hci_dev_test_flag(d, HCI_CONFIG) ||
383 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 /* Devices marked as raw-only are neither configured
387 * nor unconfigured controllers.
388 */
389 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700390 continue;
391
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200392 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700393 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700394 rp->index[count++] = cpu_to_le16(d->id);
395 BT_DBG("Added hci%u", d->id);
396 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200397 }
398
Johan Hedberg476e44c2012-10-19 20:10:46 +0300399 rp->num_controllers = cpu_to_le16(count);
400 rp_len = sizeof(*rp) + (2 * count);
401
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200402 read_unlock(&hci_dev_list_lock);
403
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200404 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
405 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200406
Johan Hedberga38528f2011-01-22 06:46:43 +0200407 kfree(rp);
408
409 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200410}
411
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200412static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
413 void *data, u16 data_len)
414{
415 struct mgmt_rp_read_unconf_index_list *rp;
416 struct hci_dev *d;
417 size_t rp_len;
418 u16 count;
419 int err;
420
421 BT_DBG("sock %p", sk);
422
423 read_lock(&hci_dev_list_lock);
424
425 count = 0;
426 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200427 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700428 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200429 count++;
430 }
431
432 rp_len = sizeof(*rp) + (2 * count);
433 rp = kmalloc(rp_len, GFP_ATOMIC);
434 if (!rp) {
435 read_unlock(&hci_dev_list_lock);
436 return -ENOMEM;
437 }
438
439 count = 0;
440 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700441 if (hci_dev_test_flag(d, HCI_SETUP) ||
442 hci_dev_test_flag(d, HCI_CONFIG) ||
443 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200444 continue;
445
446 /* Devices marked as raw-only are neither configured
447 * nor unconfigured controllers.
448 */
449 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
450 continue;
451
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200452 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700453 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200454 rp->index[count++] = cpu_to_le16(d->id);
455 BT_DBG("Added hci%u", d->id);
456 }
457 }
458
459 rp->num_controllers = cpu_to_le16(count);
460 rp_len = sizeof(*rp) + (2 * count);
461
462 read_unlock(&hci_dev_list_lock);
463
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200464 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
465 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200466
467 kfree(rp);
468
469 return err;
470}
471
Marcel Holtmann96f14742015-03-14 19:27:57 -0700472static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
473 void *data, u16 data_len)
474{
475 struct mgmt_rp_read_ext_index_list *rp;
476 struct hci_dev *d;
477 size_t rp_len;
478 u16 count;
479 int err;
480
481 BT_DBG("sock %p", sk);
482
483 read_lock(&hci_dev_list_lock);
484
485 count = 0;
486 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200487 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700488 count++;
489 }
490
491 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
492 rp = kmalloc(rp_len, GFP_ATOMIC);
493 if (!rp) {
494 read_unlock(&hci_dev_list_lock);
495 return -ENOMEM;
496 }
497
498 count = 0;
499 list_for_each_entry(d, &hci_dev_list, list) {
500 if (hci_dev_test_flag(d, HCI_SETUP) ||
501 hci_dev_test_flag(d, HCI_CONFIG) ||
502 hci_dev_test_flag(d, HCI_USER_CHANNEL))
503 continue;
504
505 /* Devices marked as raw-only are neither configured
506 * nor unconfigured controllers.
507 */
508 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
509 continue;
510
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200511 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700512 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
513 rp->entry[count].type = 0x01;
514 else
515 rp->entry[count].type = 0x00;
516 } else if (d->dev_type == HCI_AMP) {
517 rp->entry[count].type = 0x02;
518 } else {
519 continue;
520 }
521
522 rp->entry[count].bus = d->bus;
523 rp->entry[count++].index = cpu_to_le16(d->id);
524 BT_DBG("Added hci%u", d->id);
525 }
526
527 rp->num_controllers = cpu_to_le16(count);
528 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
529
530 read_unlock(&hci_dev_list_lock);
531
532 /* If this command is called at least once, then all the
533 * default index and unconfigured index events are disabled
534 * and from now on only extended index events are used.
535 */
536 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
537 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
538 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
539
540 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
541 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
542
543 kfree(rp);
544
545 return err;
546}
547
Marcel Holtmanndbece372014-07-04 18:11:55 +0200548static bool is_configured(struct hci_dev *hdev)
549{
550 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700551 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200552 return false;
553
554 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
555 !bacmp(&hdev->public_addr, BDADDR_ANY))
556 return false;
557
558 return true;
559}
560
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200561static __le32 get_missing_options(struct hci_dev *hdev)
562{
563 u32 options = 0;
564
Marcel Holtmanndbece372014-07-04 18:11:55 +0200565 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700566 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200567 options |= MGMT_OPTION_EXTERNAL_CONFIG;
568
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200569 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
570 !bacmp(&hdev->public_addr, BDADDR_ANY))
571 options |= MGMT_OPTION_PUBLIC_ADDRESS;
572
573 return cpu_to_le32(options);
574}
575
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576static int new_options(struct hci_dev *hdev, struct sock *skip)
577{
578 __le32 options = get_missing_options(hdev);
579
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200580 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
581 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200582}
583
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
585{
586 __le32 options = get_missing_options(hdev);
587
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200588 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
589 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200590}
591
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200592static int read_config_info(struct sock *sk, struct hci_dev *hdev,
593 void *data, u16 data_len)
594{
595 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200596 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200597
598 BT_DBG("sock %p %s", sk, hdev->name);
599
600 hci_dev_lock(hdev);
601
602 memset(&rp, 0, sizeof(rp));
603 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200604
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200605 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
606 options |= MGMT_OPTION_EXTERNAL_CONFIG;
607
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200608 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200609 options |= MGMT_OPTION_PUBLIC_ADDRESS;
610
611 rp.supported_options = cpu_to_le32(options);
612 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200613
614 hci_dev_unlock(hdev);
615
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200616 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
617 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200618}
619
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200620static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200621{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200622 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200624 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300625 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800626 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300627 settings |= MGMT_SETTING_CONNECTABLE;
628 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200629
Andre Guedesed3fa312012-07-24 15:03:46 -0300630 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500631 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
632 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200633 settings |= MGMT_SETTING_BREDR;
634 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700635
636 if (lmp_ssp_capable(hdev)) {
637 settings |= MGMT_SETTING_SSP;
638 settings |= MGMT_SETTING_HS;
639 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800640
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800641 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800642 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700643 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100644
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300645 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200646 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300647 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300648 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200649 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800650 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300651 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200652
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200653 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
654 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200655 settings |= MGMT_SETTING_CONFIGURATION;
656
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200657 return settings;
658}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200659
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200660static u32 get_current_settings(struct hci_dev *hdev)
661{
662 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200663
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200664 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100665 settings |= MGMT_SETTING_POWERED;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_CONNECTABLE;
669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500671 settings |= MGMT_SETTING_FAST_CONNECTABLE;
672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_DISCOVERABLE;
675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300677 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_BREDR;
681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200683 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200686 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200689 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700691 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200692 settings |= MGMT_SETTING_HS;
693
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700694 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300695 settings |= MGMT_SETTING_ADVERTISING;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800698 settings |= MGMT_SETTING_SECURE_CONN;
699
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700700 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800701 settings |= MGMT_SETTING_DEBUG_KEYS;
702
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700703 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200704 settings |= MGMT_SETTING_PRIVACY;
705
Marcel Holtmann93690c22015-03-06 10:11:21 -0800706 /* The current setting for static address has two purposes. The
707 * first is to indicate if the static address will be used and
708 * the second is to indicate if it is actually set.
709 *
710 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700711 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800712 * address is actually used decides if the flag is set or not.
713 *
714 * For single mode LE only controllers and dual-mode controllers
715 * with BR/EDR disabled, the existence of the static address will
716 * be evaluated.
717 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700718 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700719 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800720 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
721 if (bacmp(&hdev->static_addr, BDADDR_ANY))
722 settings |= MGMT_SETTING_STATIC_ADDRESS;
723 }
724
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200725 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200726}
727
Johan Hedberg333ae952015-03-17 13:48:47 +0200728static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
729{
730 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
731}
732
Johan Hedberg333ae952015-03-17 13:48:47 +0200733static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
734 struct hci_dev *hdev,
735 const void *data)
736{
737 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
738}
739
Johan Hedbergf2252572015-11-18 12:49:20 +0200740u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300741{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200742 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300743
744 /* If there's a pending mgmt command the flags will not yet have
745 * their final values, so check for this first.
746 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200747 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300748 if (cmd) {
749 struct mgmt_mode *cp = cmd->param;
750 if (cp->val == 0x01)
751 return LE_AD_GENERAL;
752 else if (cp->val == 0x02)
753 return LE_AD_LIMITED;
754 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700755 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300756 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700757 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300758 return LE_AD_GENERAL;
759 }
760
761 return 0;
762}
763
Johan Hedbergf2252572015-11-18 12:49:20 +0200764bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700765{
766 struct mgmt_pending_cmd *cmd;
767
768 /* If there's a pending mgmt command the flag will not yet have
769 * it's final value, so check for this first.
770 */
771 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
772 if (cmd) {
773 struct mgmt_mode *cp = cmd->param;
774
775 return cp->val;
776 }
777
778 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
779}
780
Johan Hedberg7d785252011-12-15 00:47:39 +0200781static void service_cache_off(struct work_struct *work)
782{
783 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300784 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500785 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200786
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700787 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200788 return;
789
Johan Hedberg890ea892013-03-15 17:06:52 -0500790 hci_req_init(&req, hdev);
791
Johan Hedberg7d785252011-12-15 00:47:39 +0200792 hci_dev_lock(hdev);
793
Johan Hedbergb1a89172015-11-25 16:15:42 +0200794 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200795 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200796
797 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500798
799 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200800}
801
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200802static void rpa_expired(struct work_struct *work)
803{
804 struct hci_dev *hdev = container_of(work, struct hci_dev,
805 rpa_expired.work);
806 struct hci_request req;
807
808 BT_DBG("");
809
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700810 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200811
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700812 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200813 return;
814
815 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200816 * controller happens in the hci_req_enable_advertising()
817 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200818 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200819 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +0200820 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200821 hci_req_run(&req, NULL);
822}
823
Johan Hedberg6a919082012-02-28 06:17:26 +0200824static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200825{
Marcel Holtmann238be782015-03-13 02:11:06 -0700826 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200827 return;
828
Johan Hedberg4f87da82012-03-02 19:55:56 +0200829 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200830 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200831
Johan Hedberg4f87da82012-03-02 19:55:56 +0200832 /* Non-mgmt controlled devices get this bit set
833 * implicitly so that pairing works for them, however
834 * for mgmt we require user-space to explicitly enable
835 * it
836 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700837 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200838}
839
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200840static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300841 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200842{
843 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200844
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200845 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200846
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300847 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200848
Johan Hedberg03811012010-12-08 00:21:06 +0200849 memset(&rp, 0, sizeof(rp));
850
Johan Hedberg03811012010-12-08 00:21:06 +0200851 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200852
853 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200854 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200855
856 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
857 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
858
859 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200860
861 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200862 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200863
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300864 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200865
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200866 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
867 sizeof(rp));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200868}
869
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200870static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
871 u8 data_len)
872{
873 eir[eir_len++] = sizeof(type) + data_len;
874 eir[eir_len++] = type;
875 memcpy(&eir[eir_len], data, data_len);
876 eir_len += data_len;
877
878 return eir_len;
879}
880
Szymon Janc6a9e90b2016-09-19 20:25:54 +0200881static inline u16 eir_append_le16(u8 *eir, u16 eir_len, u8 type, u16 data)
882{
883 eir[eir_len++] = sizeof(type) + sizeof(data);
884 eir[eir_len++] = type;
885 put_unaligned_le16(data, &eir[eir_len]);
886 eir_len += sizeof(data);
887
888 return eir_len;
889}
890
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +0200891static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
892{
893 u16 eir_len = 0;
894 size_t name_len;
895
896 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
897 eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
898 hdev->dev_class, 3);
899
Szymon Janc6a9e90b2016-09-19 20:25:54 +0200900 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
901 eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
902 hdev->appearance);
903
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +0200904 name_len = strlen(hdev->dev_name);
905 eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
906 hdev->dev_name, name_len);
907
908 name_len = strlen(hdev->short_name);
909 eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
910 hdev->short_name, name_len);
911
912 return eir_len;
913}
914
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200915static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
916 void *data, u16 data_len)
917{
Szymon Janc7d5c11d2016-09-19 20:25:52 +0200918 char buf[512];
919 struct mgmt_rp_read_ext_info *rp = (void *)buf;
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +0200920 u16 eir_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200921
922 BT_DBG("sock %p %s", sk, hdev->name);
923
Szymon Janc7d5c11d2016-09-19 20:25:52 +0200924 memset(&buf, 0, sizeof(buf));
925
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200926 hci_dev_lock(hdev);
927
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200928 bacpy(&rp->bdaddr, &hdev->bdaddr);
929
930 rp->version = hdev->hci_ver;
931 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
932
933 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
934 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200935
Szymon Janc7d5c11d2016-09-19 20:25:52 +0200936
MichaƂ Narajowskicde7a862016-09-19 20:25:53 +0200937 eir_len = append_eir_data_to_buf(hdev, rp->eir);
Szymon Janc7d5c11d2016-09-19 20:25:52 +0200938 rp->eir_len = cpu_to_le16(eir_len);
939
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200940 hci_dev_unlock(hdev);
941
942 /* If this command is called at least once, then the events
943 * for class of device and local name changes are disabled
944 * and only the new extended controller information event
945 * is used.
946 */
947 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
948 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
949 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
950
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200951 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
952 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200953}
954
955static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
956{
957 struct mgmt_ev_ext_info_changed ev;
958
959 ev.eir_len = cpu_to_le16(0);
960
961 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, &ev,
962 sizeof(ev), HCI_MGMT_EXT_INFO_EVENTS, skip);
963}
964
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200965static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200966{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200967 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200968
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200969 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
970 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200971}
972
Marcel Holtmann1904a852015-01-11 13:50:44 -0800973static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200974{
975 BT_DBG("%s status 0x%02x", hdev->name, status);
976
Johan Hedberga3172b72014-02-28 09:33:44 +0200977 if (hci_conn_count(hdev) == 0) {
978 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200979 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200980 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200981}
982
Johan Hedbergf2252572015-11-18 12:49:20 +0200983void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700984{
985 struct mgmt_ev_advertising_added ev;
986
987 ev.instance = instance;
988
989 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
990}
991
Johan Hedbergf2252572015-11-18 12:49:20 +0200992void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
993 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700994{
995 struct mgmt_ev_advertising_removed ev;
996
997 ev.instance = instance;
998
999 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1000}
1001
Florian Grandel7816b822015-06-18 03:16:45 +02001002static void cancel_adv_timeout(struct hci_dev *hdev)
1003{
1004 if (hdev->adv_instance_timeout) {
1005 hdev->adv_instance_timeout = 0;
1006 cancel_delayed_work(&hdev->adv_instance_expire);
1007 }
1008}
1009
Johan Hedberg8b064a32014-02-24 14:52:22 +02001010static int clean_up_hci_state(struct hci_dev *hdev)
1011{
1012 struct hci_request req;
1013 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001014 bool discov_stopped;
1015 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001016
1017 hci_req_init(&req, hdev);
1018
1019 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1020 test_bit(HCI_PSCAN, &hdev->flags)) {
1021 u8 scan = 0x00;
1022 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1023 }
1024
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001025 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001026
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001027 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001028 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001029
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001030 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001031
1032 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001033 /* 0x15 == Terminated due to Power Off */
1034 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001035 }
1036
Johan Hedberg23a48092014-07-08 16:05:06 +03001037 err = hci_req_run(&req, clean_up_hci_complete);
1038 if (!err && discov_stopped)
1039 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1040
1041 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001042}
1043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001044static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001045 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001047 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001048 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001049 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001051 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052
Johan Hedberga7e80f22013-01-09 16:05:19 +02001053 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001054 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1055 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001056
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001057 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001058
Johan Hedberg333ae952015-03-17 13:48:47 +02001059 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001060 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1061 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001062 goto failed;
1063 }
1064
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001065 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001066 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001067 goto failed;
1068 }
1069
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001070 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1071 if (!cmd) {
1072 err = -ENOMEM;
1073 goto failed;
1074 }
1075
Johan Hedberg8b064a32014-02-24 14:52:22 +02001076 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001077 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001078 err = 0;
1079 } else {
1080 /* Disconnect connections, stop scans, etc */
1081 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001082 if (!err)
1083 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1084 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001085
Johan Hedberg8b064a32014-02-24 14:52:22 +02001086 /* ENODATA means there were no HCI commands queued */
1087 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001088 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001089 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1090 err = 0;
1091 }
1092 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001093
1094failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001095 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001096 return err;
1097}
1098
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001099static int new_settings(struct hci_dev *hdev, struct sock *skip)
1100{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001101 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001102
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001103 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1104 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001105}
1106
Johan Hedberg91a668b2014-07-09 13:28:26 +03001107int mgmt_new_settings(struct hci_dev *hdev)
1108{
1109 return new_settings(hdev, NULL);
1110}
1111
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001112struct cmd_lookup {
1113 struct sock *sk;
1114 struct hci_dev *hdev;
1115 u8 mgmt_status;
1116};
1117
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001118static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001119{
1120 struct cmd_lookup *match = data;
1121
1122 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1123
1124 list_del(&cmd->list);
1125
1126 if (match->sk == NULL) {
1127 match->sk = cmd->sk;
1128 sock_hold(match->sk);
1129 }
1130
1131 mgmt_pending_free(cmd);
1132}
1133
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001134static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001135{
1136 u8 *status = data;
1137
Johan Hedberga69e8372015-03-06 21:08:53 +02001138 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001139 mgmt_pending_remove(cmd);
1140}
1141
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001142static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001143{
1144 if (cmd->cmd_complete) {
1145 u8 *status = data;
1146
1147 cmd->cmd_complete(cmd, *status);
1148 mgmt_pending_remove(cmd);
1149
1150 return;
1151 }
1152
1153 cmd_status_rsp(cmd, data);
1154}
1155
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001156static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001157{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001158 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1159 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001160}
1161
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001162static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001163{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001164 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1165 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001166}
1167
Johan Hedberge6fe7982013-10-02 15:45:22 +03001168static u8 mgmt_bredr_support(struct hci_dev *hdev)
1169{
1170 if (!lmp_bredr_capable(hdev))
1171 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001172 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001173 return MGMT_STATUS_REJECTED;
1174 else
1175 return MGMT_STATUS_SUCCESS;
1176}
1177
1178static u8 mgmt_le_support(struct hci_dev *hdev)
1179{
1180 if (!lmp_le_capable(hdev))
1181 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001182 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001183 return MGMT_STATUS_REJECTED;
1184 else
1185 return MGMT_STATUS_SUCCESS;
1186}
1187
Johan Hedbergaed1a882015-11-22 17:24:44 +03001188void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001189{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001190 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001191
1192 BT_DBG("status 0x%02x", status);
1193
1194 hci_dev_lock(hdev);
1195
Johan Hedberg333ae952015-03-17 13:48:47 +02001196 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001197 if (!cmd)
1198 goto unlock;
1199
1200 if (status) {
1201 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001202 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001203 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001204 goto remove_cmd;
1205 }
1206
Johan Hedbergaed1a882015-11-22 17:24:44 +03001207 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1208 hdev->discov_timeout > 0) {
1209 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1210 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001211 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001212
1213 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001214 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001215
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001216remove_cmd:
1217 mgmt_pending_remove(cmd);
1218
1219unlock:
1220 hci_dev_unlock(hdev);
1221}
1222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001223static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001224 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001225{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001226 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001227 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001228 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001229 int err;
1230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001231 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001232
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001233 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1234 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001235 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1236 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001237
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001238 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001239 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1240 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001241
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001242 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001243
1244 /* Disabling discoverable requires that no timeout is set,
1245 * and enabling limited discoverable requires a timeout.
1246 */
1247 if ((cp->val == 0x00 && timeout > 0) ||
1248 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001249 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1250 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001252 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001253
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001254 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001255 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1256 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001257 goto failed;
1258 }
1259
Johan Hedberg333ae952015-03-17 13:48:47 +02001260 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1261 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001262 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1263 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001264 goto failed;
1265 }
1266
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001267 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001268 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1269 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001270 goto failed;
1271 }
1272
1273 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001274 bool changed = false;
1275
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001276 /* Setting limited discoverable when powered off is
1277 * not a valid operation since it requires a timeout
1278 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1279 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001280 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001281 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001282 changed = true;
1283 }
1284
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001285 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001286 if (err < 0)
1287 goto failed;
1288
1289 if (changed)
1290 err = new_settings(hdev, sk);
1291
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001292 goto failed;
1293 }
1294
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001295 /* If the current mode is the same, then just update the timeout
1296 * value with the new value. And if only the timeout gets updated,
1297 * then no need for any HCI transactions.
1298 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001299 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1300 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1301 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001302 cancel_delayed_work(&hdev->discov_off);
1303 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001304
Marcel Holtmann36261542013-10-15 08:28:51 -07001305 if (cp->val && hdev->discov_timeout > 0) {
1306 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001307 queue_delayed_work(hdev->req_workqueue,
1308 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001309 }
1310
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001311 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001312 goto failed;
1313 }
1314
1315 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1316 if (!cmd) {
1317 err = -ENOMEM;
1318 goto failed;
1319 }
1320
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001321 /* Cancel any potential discoverable timeout that might be
1322 * still active and store new timeout value. The arming of
1323 * the timeout happens in the complete handler.
1324 */
1325 cancel_delayed_work(&hdev->discov_off);
1326 hdev->discov_timeout = timeout;
1327
Johan Hedbergaed1a882015-11-22 17:24:44 +03001328 if (cp->val)
1329 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1330 else
1331 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1332
Johan Hedbergb456f872013-10-19 23:38:22 +03001333 /* Limited discoverable mode */
1334 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001335 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001336 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001337 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001338
Johan Hedbergaed1a882015-11-22 17:24:44 +03001339 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1340 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001341
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001342failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001343 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001344 return err;
1345}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001346
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001347void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001348{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001349 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001350
1351 BT_DBG("status 0x%02x", status);
1352
1353 hci_dev_lock(hdev);
1354
Johan Hedberg333ae952015-03-17 13:48:47 +02001355 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001356 if (!cmd)
1357 goto unlock;
1358
Johan Hedberg37438c12013-10-14 16:20:05 +03001359 if (status) {
1360 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001361 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001362 goto remove_cmd;
1363 }
1364
Johan Hedberg2b76f452013-03-15 17:07:04 -05001365 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001366 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001367
Johan Hedberg37438c12013-10-14 16:20:05 +03001368remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001369 mgmt_pending_remove(cmd);
1370
1371unlock:
1372 hci_dev_unlock(hdev);
1373}
1374
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001375static int set_connectable_update_settings(struct hci_dev *hdev,
1376 struct sock *sk, u8 val)
1377{
1378 bool changed = false;
1379 int err;
1380
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001381 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001382 changed = true;
1383
1384 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001385 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001386 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001387 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1388 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001389 }
1390
1391 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1392 if (err < 0)
1393 return err;
1394
Johan Hedberg562064e2014-07-08 16:35:34 +03001395 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001396 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001397 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001398 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001399 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001400
1401 return 0;
1402}
1403
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001405 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001406{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001407 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001408 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001409 int err;
1410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001411 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001412
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001413 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1414 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001415 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1416 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001417
Johan Hedberga7e80f22013-01-09 16:05:19 +02001418 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001419 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1420 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001421
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001422 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001423
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001424 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001425 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001426 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001427 }
1428
Johan Hedberg333ae952015-03-17 13:48:47 +02001429 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1430 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001431 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1432 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001433 goto failed;
1434 }
1435
Johan Hedberg73f22f62010-12-29 16:00:25 +02001436 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1437 if (!cmd) {
1438 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001439 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001440 }
1441
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001442 if (cp->val) {
1443 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1444 } else {
1445 if (hdev->discov_timeout > 0)
1446 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001447
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001448 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1449 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1450 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001451 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001452
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001453 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1454 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001455
1456failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001457 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001458 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001459}
1460
Johan Hedbergb2939472014-07-30 09:22:23 +03001461static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001462 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001463{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001464 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001465 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001466 int err;
1467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001468 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001469
Johan Hedberga7e80f22013-01-09 16:05:19 +02001470 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001471 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1472 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001474 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001475
1476 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001477 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001478 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001479 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001480
Johan Hedbergb2939472014-07-30 09:22:23 +03001481 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001482 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001483 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001484
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001485 if (changed) {
1486 /* In limited privacy mode the change of bondable mode
1487 * may affect the local advertising address.
1488 */
1489 if (hdev_is_powered(hdev) &&
1490 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1491 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1492 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1493 queue_work(hdev->req_workqueue,
1494 &hdev->discoverable_update);
1495
Marcel Holtmann55594352013-10-06 16:11:57 -07001496 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001497 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001498
Marcel Holtmann55594352013-10-06 16:11:57 -07001499unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001500 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001501 return err;
1502}
1503
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001504static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1505 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001506{
1507 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001508 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001509 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001510 int err;
1511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001512 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001513
Johan Hedberge6fe7982013-10-02 15:45:22 +03001514 status = mgmt_bredr_support(hdev);
1515 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001516 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1517 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001518
Johan Hedberga7e80f22013-01-09 16:05:19 +02001519 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001520 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1521 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001522
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001523 hci_dev_lock(hdev);
1524
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001525 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001526 bool changed = false;
1527
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001528 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001529 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001530 changed = true;
1531 }
1532
1533 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1534 if (err < 0)
1535 goto failed;
1536
1537 if (changed)
1538 err = new_settings(hdev, sk);
1539
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001540 goto failed;
1541 }
1542
Johan Hedberg333ae952015-03-17 13:48:47 +02001543 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001544 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1545 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001546 goto failed;
1547 }
1548
1549 val = !!cp->val;
1550
1551 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1552 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1553 goto failed;
1554 }
1555
1556 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1557 if (!cmd) {
1558 err = -ENOMEM;
1559 goto failed;
1560 }
1561
1562 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1563 if (err < 0) {
1564 mgmt_pending_remove(cmd);
1565 goto failed;
1566 }
1567
1568failed:
1569 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001570 return err;
1571}
1572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001573static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001574{
1575 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001576 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001577 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001578 int err;
1579
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001580 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001581
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001582 status = mgmt_bredr_support(hdev);
1583 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001584 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001585
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001586 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001587 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1588 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001589
Johan Hedberga7e80f22013-01-09 16:05:19 +02001590 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001591 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1592 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001593
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001594 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001595
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001596 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001597 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001598
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001599 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001600 changed = !hci_dev_test_and_set_flag(hdev,
1601 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001602 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001603 changed = hci_dev_test_and_clear_flag(hdev,
1604 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001605 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001606 changed = hci_dev_test_and_clear_flag(hdev,
1607 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001608 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001609 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001610 }
1611
1612 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1613 if (err < 0)
1614 goto failed;
1615
1616 if (changed)
1617 err = new_settings(hdev, sk);
1618
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001619 goto failed;
1620 }
1621
Johan Hedberg333ae952015-03-17 13:48:47 +02001622 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001623 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1624 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001625 goto failed;
1626 }
1627
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001628 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001629 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1630 goto failed;
1631 }
1632
1633 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1634 if (!cmd) {
1635 err = -ENOMEM;
1636 goto failed;
1637 }
1638
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001639 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001640 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1641 sizeof(cp->val), &cp->val);
1642
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001643 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001644 if (err < 0) {
1645 mgmt_pending_remove(cmd);
1646 goto failed;
1647 }
1648
1649failed:
1650 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001651 return err;
1652}
1653
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001654static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001655{
1656 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001657 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001658 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001659 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001661 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001662
Johan Hedberge6fe7982013-10-02 15:45:22 +03001663 status = mgmt_bredr_support(hdev);
1664 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001665 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001666
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001667 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001668 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1669 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001670
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001671 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001672 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1673 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001674
Johan Hedberga7e80f22013-01-09 16:05:19 +02001675 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001676 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1677 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001678
Marcel Holtmannee392692013-10-01 22:59:23 -07001679 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001680
Johan Hedberg333ae952015-03-17 13:48:47 +02001681 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001682 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1683 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001684 goto unlock;
1685 }
1686
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001687 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001688 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001689 } else {
1690 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001691 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1692 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001693 goto unlock;
1694 }
1695
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001696 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001697 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001698
1699 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1700 if (err < 0)
1701 goto unlock;
1702
1703 if (changed)
1704 err = new_settings(hdev, sk);
1705
1706unlock:
1707 hci_dev_unlock(hdev);
1708 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001709}
1710
Marcel Holtmann1904a852015-01-11 13:50:44 -08001711static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001712{
1713 struct cmd_lookup match = { NULL, hdev };
1714
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301715 hci_dev_lock(hdev);
1716
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001717 if (status) {
1718 u8 mgmt_err = mgmt_status(status);
1719
1720 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1721 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301722 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001723 }
1724
1725 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1726
1727 new_settings(hdev, match.sk);
1728
1729 if (match.sk)
1730 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001731
1732 /* Make sure the controller has a good default for
1733 * advertising data. Restrict the update to when LE
1734 * has actually been enabled. During power on, the
1735 * update in powered_update_hci will take care of it.
1736 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001737 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001738 struct hci_request req;
1739
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001740 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001741 __hci_req_update_adv_data(&req, 0x00);
1742 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001743 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001744 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001745 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301746
1747unlock:
1748 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001749}
1750
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001751static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001752{
1753 struct mgmt_mode *cp = data;
1754 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001755 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001756 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001757 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001758 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001760 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001761
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001762 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001763 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1764 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001765
Johan Hedberga7e80f22013-01-09 16:05:19 +02001766 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001767 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1768 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001769
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001770 /* Bluetooth single mode LE only controllers or dual-mode
1771 * controllers configured as LE only devices, do not allow
1772 * switching LE off. These have either LE enabled explicitly
1773 * or BR/EDR has been previously switched off.
1774 *
1775 * When trying to enable an already enabled LE, then gracefully
1776 * send a positive response. Trying to disable it however will
1777 * result into rejection.
1778 */
1779 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1780 if (cp->val == 0x01)
1781 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1782
Johan Hedberga69e8372015-03-06 21:08:53 +02001783 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1784 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001785 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001786
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001787 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001788
1789 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001790 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001791
Florian Grandel847818d2015-06-18 03:16:46 +02001792 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001793 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001794
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001795 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001796 bool changed = false;
1797
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001798 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001799 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001800 changed = true;
1801 }
1802
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001803 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001804 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001805 changed = true;
1806 }
1807
Johan Hedberg06199cf2012-02-22 16:37:11 +02001808 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1809 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001810 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001811
1812 if (changed)
1813 err = new_settings(hdev, sk);
1814
Johan Hedberg1de028c2012-02-29 19:55:35 -08001815 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001816 }
1817
Johan Hedberg333ae952015-03-17 13:48:47 +02001818 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1819 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001820 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1821 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001822 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001823 }
1824
1825 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1826 if (!cmd) {
1827 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001828 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001829 }
1830
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001831 hci_req_init(&req, hdev);
1832
Johan Hedberg06199cf2012-02-22 16:37:11 +02001833 memset(&hci_cp, 0, sizeof(hci_cp));
1834
1835 if (val) {
1836 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001837 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001838 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001839 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001840 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001841 }
1842
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001843 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1844 &hci_cp);
1845
1846 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301847 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001848 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001849
Johan Hedberg1de028c2012-02-29 19:55:35 -08001850unlock:
1851 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001852 return err;
1853}
1854
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001855/* This is a helper function to test for pending mgmt commands that can
1856 * cause CoD or EIR HCI commands. We can only allow one such pending
1857 * mgmt command at a time since otherwise we cannot easily track what
1858 * the current values are, will be, and based on that calculate if a new
1859 * HCI command needs to be sent and if yes with what value.
1860 */
1861static bool pending_eir_or_class(struct hci_dev *hdev)
1862{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001863 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001864
1865 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1866 switch (cmd->opcode) {
1867 case MGMT_OP_ADD_UUID:
1868 case MGMT_OP_REMOVE_UUID:
1869 case MGMT_OP_SET_DEV_CLASS:
1870 case MGMT_OP_SET_POWERED:
1871 return true;
1872 }
1873 }
1874
1875 return false;
1876}
1877
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001878static const u8 bluetooth_base_uuid[] = {
1879 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1880 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1881};
1882
1883static u8 get_uuid_size(const u8 *uuid)
1884{
1885 u32 val;
1886
1887 if (memcmp(uuid, bluetooth_base_uuid, 12))
1888 return 128;
1889
1890 val = get_unaligned_le32(&uuid[12]);
1891 if (val > 0xffff)
1892 return 32;
1893
1894 return 16;
1895}
1896
Johan Hedberg92da6092013-03-15 17:06:55 -05001897static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1898{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001899 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001900
1901 hci_dev_lock(hdev);
1902
Johan Hedberg333ae952015-03-17 13:48:47 +02001903 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001904 if (!cmd)
1905 goto unlock;
1906
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001907 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1908 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001909
1910 mgmt_pending_remove(cmd);
1911
1912unlock:
1913 hci_dev_unlock(hdev);
1914}
1915
Marcel Holtmann1904a852015-01-11 13:50:44 -08001916static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001917{
1918 BT_DBG("status 0x%02x", status);
1919
1920 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1921}
1922
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001923static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001924{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001925 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001926 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001927 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001928 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001929 int err;
1930
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001931 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001932
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001933 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001934
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001935 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001936 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1937 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001938 goto failed;
1939 }
1940
Andre Guedes92c4c202012-06-07 19:05:44 -03001941 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001942 if (!uuid) {
1943 err = -ENOMEM;
1944 goto failed;
1945 }
1946
1947 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001948 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001949 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001950
Johan Hedbergde66aa62013-01-27 00:31:27 +02001951 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001952
Johan Hedberg890ea892013-03-15 17:06:52 -05001953 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001954
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001955 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001956 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001957
Johan Hedberg92da6092013-03-15 17:06:55 -05001958 err = hci_req_run(&req, add_uuid_complete);
1959 if (err < 0) {
1960 if (err != -ENODATA)
1961 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001962
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001963 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1964 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001965 goto failed;
1966 }
1967
1968 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001969 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001970 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001971 goto failed;
1972 }
1973
1974 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001975
1976failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001977 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001978 return err;
1979}
1980
Johan Hedberg24b78d02012-02-23 23:24:30 +02001981static bool enable_service_cache(struct hci_dev *hdev)
1982{
1983 if (!hdev_is_powered(hdev))
1984 return false;
1985
Marcel Holtmann238be782015-03-13 02:11:06 -07001986 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001987 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1988 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001989 return true;
1990 }
1991
1992 return false;
1993}
1994
Marcel Holtmann1904a852015-01-11 13:50:44 -08001995static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001996{
1997 BT_DBG("status 0x%02x", status);
1998
1999 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2000}
2001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002002static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002003 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002005 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002006 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002007 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002008 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 -05002009 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002010 int err, found;
2011
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002012 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002013
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002014 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002015
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002016 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002017 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2018 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002019 goto unlock;
2020 }
2021
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002022 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002023 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002024
Johan Hedberg24b78d02012-02-23 23:24:30 +02002025 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002026 err = mgmt_cmd_complete(sk, hdev->id,
2027 MGMT_OP_REMOVE_UUID,
2028 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002029 goto unlock;
2030 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002031
Johan Hedberg9246a862012-02-23 21:33:16 +02002032 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002033 }
2034
2035 found = 0;
2036
Johan Hedberg056341c2013-01-27 00:31:30 +02002037 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002038 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2039 continue;
2040
2041 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002042 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002043 found++;
2044 }
2045
2046 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002047 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2048 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002049 goto unlock;
2050 }
2051
Johan Hedberg9246a862012-02-23 21:33:16 +02002052update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002053 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002054
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002055 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002056 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002057
Johan Hedberg92da6092013-03-15 17:06:55 -05002058 err = hci_req_run(&req, remove_uuid_complete);
2059 if (err < 0) {
2060 if (err != -ENODATA)
2061 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002062
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002063 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2064 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002065 goto unlock;
2066 }
2067
2068 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002069 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002070 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002071 goto unlock;
2072 }
2073
2074 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002075
2076unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002077 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002078 return err;
2079}
2080
Marcel Holtmann1904a852015-01-11 13:50:44 -08002081static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002082{
2083 BT_DBG("status 0x%02x", status);
2084
2085 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2086}
2087
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002088static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002090{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002091 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002092 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002093 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002094 int err;
2095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002096 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002097
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002098 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002099 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2100 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002101
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002102 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002103
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002104 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002105 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2106 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002107 goto unlock;
2108 }
2109
2110 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002111 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2112 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002113 goto unlock;
2114 }
2115
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002116 hdev->major_class = cp->major;
2117 hdev->minor_class = cp->minor;
2118
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002119 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002120 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2121 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002122 goto unlock;
2123 }
2124
Johan Hedberg890ea892013-03-15 17:06:52 -05002125 hci_req_init(&req, hdev);
2126
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002127 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002128 hci_dev_unlock(hdev);
2129 cancel_delayed_work_sync(&hdev->service_cache);
2130 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002131 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002132 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002133
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002134 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002135
Johan Hedberg92da6092013-03-15 17:06:55 -05002136 err = hci_req_run(&req, set_class_complete);
2137 if (err < 0) {
2138 if (err != -ENODATA)
2139 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002140
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002141 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2142 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002143 goto unlock;
2144 }
2145
2146 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002147 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002148 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002149 goto unlock;
2150 }
2151
2152 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002153
Johan Hedbergb5235a62012-02-21 14:32:24 +02002154unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002155 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002156 return err;
2157}
2158
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002159static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002160 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002161{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002162 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002163 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2164 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002165 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002166 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002167 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002168
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002169 BT_DBG("request for %s", hdev->name);
2170
2171 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002172 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2173 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002174
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002175 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002176 if (key_count > max_key_count) {
2177 BT_ERR("load_link_keys: too big key_count value %u",
2178 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002179 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2180 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002181 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002182
Johan Hedberg86742e12011-11-07 23:13:38 +02002183 expected_len = sizeof(*cp) + key_count *
2184 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002185 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002186 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002187 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002188 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2189 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002190 }
2191
Johan Hedberg4ae14302013-01-20 14:27:13 +02002192 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002193 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2194 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002196 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002197 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002198
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002199 for (i = 0; i < key_count; i++) {
2200 struct mgmt_link_key_info *key = &cp->keys[i];
2201
Marcel Holtmann8e991132014-01-10 02:07:25 -08002202 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002203 return mgmt_cmd_status(sk, hdev->id,
2204 MGMT_OP_LOAD_LINK_KEYS,
2205 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002206 }
2207
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002208 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002209
2210 hci_link_keys_clear(hdev);
2211
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002212 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002213 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002214 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002215 changed = hci_dev_test_and_clear_flag(hdev,
2216 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002217
2218 if (changed)
2219 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002220
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002221 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002222 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002223
Johan Hedberg58e92932014-06-24 14:00:26 +03002224 /* Always ignore debug keys and require a new pairing if
2225 * the user wants to use them.
2226 */
2227 if (key->type == HCI_LK_DEBUG_COMBINATION)
2228 continue;
2229
Johan Hedberg7652ff62014-06-24 13:15:49 +03002230 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2231 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002232 }
2233
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002234 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002235
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002236 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002237
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002238 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002239}
2240
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002241static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002242 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002243{
2244 struct mgmt_ev_device_unpaired ev;
2245
2246 bacpy(&ev.addr.bdaddr, bdaddr);
2247 ev.addr.type = addr_type;
2248
2249 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002250 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002251}
2252
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002253static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002254 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002255{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002256 struct mgmt_cp_unpair_device *cp = data;
2257 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002258 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002259 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002261 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002262 int err;
2263
Johan Hedberga8a1d192011-11-10 15:54:38 +02002264 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002265 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2266 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002267
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002268 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002269 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2270 MGMT_STATUS_INVALID_PARAMS,
2271 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002272
Johan Hedberg118da702013-01-20 14:27:20 +02002273 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002274 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2275 MGMT_STATUS_INVALID_PARAMS,
2276 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002277
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002278 hci_dev_lock(hdev);
2279
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002280 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002281 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2282 MGMT_STATUS_NOT_POWERED, &rp,
2283 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002284 goto unlock;
2285 }
2286
Johan Hedberge0b2b272014-02-18 17:14:31 +02002287 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002288 /* If disconnection is requested, then look up the
2289 * connection. If the remote device is connected, it
2290 * will be later used to terminate the link.
2291 *
2292 * Setting it to NULL explicitly will cause no
2293 * termination of the link.
2294 */
2295 if (cp->disconnect)
2296 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2297 &cp->addr.bdaddr);
2298 else
2299 conn = NULL;
2300
Johan Hedberg124f6e32012-02-09 13:50:12 +02002301 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002302 if (err < 0) {
2303 err = mgmt_cmd_complete(sk, hdev->id,
2304 MGMT_OP_UNPAIR_DEVICE,
2305 MGMT_STATUS_NOT_PAIRED, &rp,
2306 sizeof(rp));
2307 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002308 }
2309
Johan Hedbergec182f02015-10-21 18:03:03 +03002310 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002311 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002312
Johan Hedbergec182f02015-10-21 18:03:03 +03002313 /* LE address type */
2314 addr_type = le_addr_type(cp->addr.type);
2315
2316 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2317
2318 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002319 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002320 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2321 MGMT_STATUS_NOT_PAIRED, &rp,
2322 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002323 goto unlock;
2324 }
2325
Johan Hedbergec182f02015-10-21 18:03:03 +03002326 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2327 if (!conn) {
2328 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2329 goto done;
2330 }
2331
Johan Hedbergc81d5552015-10-22 09:38:35 +03002332 /* Abort any ongoing SMP pairing */
2333 smp_cancel_pairing(conn);
2334
Johan Hedbergec182f02015-10-21 18:03:03 +03002335 /* Defer clearing up the connection parameters until closing to
2336 * give a chance of keeping them if a repairing happens.
2337 */
2338 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2339
Johan Hedbergfc643612015-10-22 09:38:31 +03002340 /* Disable auto-connection parameters if present */
2341 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2342 if (params) {
2343 if (params->explicit_connect)
2344 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2345 else
2346 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2347 }
2348
Johan Hedbergec182f02015-10-21 18:03:03 +03002349 /* If disconnection is not requested, then clear the connection
2350 * variable so that the link is not terminated.
2351 */
2352 if (!cp->disconnect)
2353 conn = NULL;
2354
2355done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002356 /* If the connection variable is set, then termination of the
2357 * link is requested.
2358 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002359 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002360 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2361 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002362 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002363 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002364 }
2365
Johan Hedberg124f6e32012-02-09 13:50:12 +02002366 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002368 if (!cmd) {
2369 err = -ENOMEM;
2370 goto unlock;
2371 }
2372
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002373 cmd->cmd_complete = addr_cmd_complete;
2374
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002375 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002376 if (err < 0)
2377 mgmt_pending_remove(cmd);
2378
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002379unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002381 return err;
2382}
2383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002384static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002385 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002386{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002387 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002388 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002389 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002390 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002391 int err;
2392
2393 BT_DBG("");
2394
Johan Hedberg06a63b12013-01-20 14:27:21 +02002395 memset(&rp, 0, sizeof(rp));
2396 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2397 rp.addr.type = cp->addr.type;
2398
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002400 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2401 MGMT_STATUS_INVALID_PARAMS,
2402 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002403
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002404 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002405
2406 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002407 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2408 MGMT_STATUS_NOT_POWERED, &rp,
2409 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002410 goto failed;
2411 }
2412
Johan Hedberg333ae952015-03-17 13:48:47 +02002413 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002414 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2415 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002416 goto failed;
2417 }
2418
Andre Guedes591f47f2012-04-24 21:02:49 -03002419 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002420 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2421 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002422 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002423 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2424 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002425
Vishal Agarwalf9607272012-06-13 05:32:43 +05302426 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002427 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2428 MGMT_STATUS_NOT_CONNECTED, &rp,
2429 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002430 goto failed;
2431 }
2432
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002433 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002434 if (!cmd) {
2435 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002436 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002437 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438
Johan Hedbergf5818c22014-12-05 13:36:02 +02002439 cmd->cmd_complete = generic_cmd_complete;
2440
Johan Hedberge3f2f922014-08-18 20:33:33 +03002441 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002442 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002443 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002444
2445failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002446 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002447 return err;
2448}
2449
Andre Guedes57c14772012-04-24 21:02:50 -03002450static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002451{
2452 switch (link_type) {
2453 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002454 switch (addr_type) {
2455 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002456 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002457
Johan Hedberg48264f02011-11-09 13:58:58 +02002458 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002459 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002460 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002461 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002462
Johan Hedberg4c659c32011-11-07 23:13:39 +02002463 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002464 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002465 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002466 }
2467}
2468
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002469static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2470 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002471{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002472 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002473 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002474 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002475 int err;
2476 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002477
2478 BT_DBG("");
2479
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002480 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002481
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002482 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002483 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2484 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002485 goto unlock;
2486 }
2487
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002488 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002489 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2490 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002491 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002492 }
2493
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002494 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002495 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002496 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002497 err = -ENOMEM;
2498 goto unlock;
2499 }
2500
Johan Hedberg2784eb42011-01-21 13:56:35 +02002501 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002502 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002503 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2504 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002505 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002506 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002507 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002508 continue;
2509 i++;
2510 }
2511
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002512 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002513
Johan Hedberg4c659c32011-11-07 23:13:39 +02002514 /* Recalculate length in case of filtered SCO connections, etc */
2515 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002516
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002517 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2518 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002519
Johan Hedberga38528f2011-01-22 06:46:43 +02002520 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002521
2522unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002523 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002524 return err;
2525}
2526
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002527static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002529{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002530 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002531 int err;
2532
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002533 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002534 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002535 if (!cmd)
2536 return -ENOMEM;
2537
Johan Hedbergd8457692012-02-17 14:24:57 +02002538 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002540 if (err < 0)
2541 mgmt_pending_remove(cmd);
2542
2543 return err;
2544}
2545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002548{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002549 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002550 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002551 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002552 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002553 int err;
2554
2555 BT_DBG("");
2556
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002557 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002558
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002559 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002560 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2561 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002562 goto failed;
2563 }
2564
Johan Hedbergd8457692012-02-17 14:24:57 +02002565 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002566 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002567 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2568 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002569 goto failed;
2570 }
2571
2572 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002573 struct mgmt_cp_pin_code_neg_reply ncp;
2574
2575 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002576
2577 BT_ERR("PIN code is not 16 bytes long");
2578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002579 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002580 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002581 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2582 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002583
2584 goto failed;
2585 }
2586
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002587 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002588 if (!cmd) {
2589 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002590 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002591 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002592
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002593 cmd->cmd_complete = addr_cmd_complete;
2594
Johan Hedbergd8457692012-02-17 14:24:57 +02002595 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002596 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002597 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002598
2599 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2600 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002601 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002602
2603failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002604 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002605 return err;
2606}
2607
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002608static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2609 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002610{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002611 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002612
2613 BT_DBG("");
2614
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002615 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002616 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2617 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002619 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002620
2621 hdev->io_capability = cp->io_capability;
2622
2623 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002624 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002625
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002626 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002627
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002628 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2629 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002630}
2631
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002632static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002633{
2634 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002635 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002636
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002637 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002638 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2639 continue;
2640
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641 if (cmd->user_data != conn)
2642 continue;
2643
2644 return cmd;
2645 }
2646
2647 return NULL;
2648}
2649
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002650static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002651{
2652 struct mgmt_rp_pair_device rp;
2653 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002654 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002655
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002656 bacpy(&rp.addr.bdaddr, &conn->dst);
2657 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002658
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002659 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2660 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002661
2662 /* So we don't get further callbacks for this connection */
2663 conn->connect_cfm_cb = NULL;
2664 conn->security_cfm_cb = NULL;
2665 conn->disconn_cfm_cb = NULL;
2666
David Herrmann76a68ba2013-04-06 20:28:37 +02002667 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002668
2669 /* The device is paired so there is no need to remove
2670 * its connection parameters anymore.
2671 */
2672 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002673
2674 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002675
2676 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002677}
2678
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002679void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2680{
2681 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002682 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002683
2684 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002685 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002686 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002687 mgmt_pending_remove(cmd);
2688 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002689}
2690
Johan Hedberge9a416b2011-02-19 12:05:56 -03002691static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2692{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002693 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002694
2695 BT_DBG("status %u", status);
2696
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002697 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002698 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002699 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002700 return;
2701 }
2702
2703 cmd->cmd_complete(cmd, mgmt_status(status));
2704 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002705}
2706
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002707static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302708{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002709 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302710
2711 BT_DBG("status %u", status);
2712
2713 if (!status)
2714 return;
2715
2716 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002717 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302718 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002719 return;
2720 }
2721
2722 cmd->cmd_complete(cmd, mgmt_status(status));
2723 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302724}
2725
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002726static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002727 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002728{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002729 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002730 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002731 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732 u8 sec_level, auth_type;
2733 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002734 int err;
2735
2736 BT_DBG("");
2737
Szymon Jancf950a30e2013-01-18 12:48:07 +01002738 memset(&rp, 0, sizeof(rp));
2739 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2740 rp.addr.type = cp->addr.type;
2741
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002742 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002743 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2744 MGMT_STATUS_INVALID_PARAMS,
2745 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002746
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002747 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002748 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2749 MGMT_STATUS_INVALID_PARAMS,
2750 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002752 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002753
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002754 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002755 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2756 MGMT_STATUS_NOT_POWERED, &rp,
2757 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002758 goto unlock;
2759 }
2760
Johan Hedberg55e76b32015-03-10 22:34:40 +02002761 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2762 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2763 MGMT_STATUS_ALREADY_PAIRED, &rp,
2764 sizeof(rp));
2765 goto unlock;
2766 }
2767
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002768 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002769 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002770
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002771 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002772 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2773 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002774 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002775 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002776 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002777
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002778 /* When pairing a new device, it is expected to remember
2779 * this device for future connections. Adding the connection
2780 * parameter information ahead of time allows tracking
2781 * of the slave preferred values and will speed up any
2782 * further connection establishment.
2783 *
2784 * If connection parameters already exist, then they
2785 * will be kept and this function does nothing.
2786 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002787 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2788
2789 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2790 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002791
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002792 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2793 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002794 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002795 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002796
Ville Tervo30e76272011-02-22 16:10:53 -03002797 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002798 int status;
2799
2800 if (PTR_ERR(conn) == -EBUSY)
2801 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002802 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2803 status = MGMT_STATUS_NOT_SUPPORTED;
2804 else if (PTR_ERR(conn) == -ECONNREFUSED)
2805 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002806 else
2807 status = MGMT_STATUS_CONNECT_FAILED;
2808
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002809 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2810 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002811 goto unlock;
2812 }
2813
2814 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002815 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002816 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2817 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002818 goto unlock;
2819 }
2820
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002821 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002822 if (!cmd) {
2823 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002824 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002825 goto unlock;
2826 }
2827
Johan Hedberg04ab2742014-12-05 13:36:04 +02002828 cmd->cmd_complete = pairing_complete;
2829
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002830 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002831 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002832 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002833 conn->security_cfm_cb = pairing_complete_cb;
2834 conn->disconn_cfm_cb = pairing_complete_cb;
2835 } else {
2836 conn->connect_cfm_cb = le_pairing_complete_cb;
2837 conn->security_cfm_cb = le_pairing_complete_cb;
2838 conn->disconn_cfm_cb = le_pairing_complete_cb;
2839 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002840
Johan Hedberge9a416b2011-02-19 12:05:56 -03002841 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002842 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002843
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002844 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002845 hci_conn_security(conn, sec_level, auth_type, true)) {
2846 cmd->cmd_complete(cmd, 0);
2847 mgmt_pending_remove(cmd);
2848 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002849
2850 err = 0;
2851
2852unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002853 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002854 return err;
2855}
2856
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002857static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2858 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002859{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002860 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002861 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002862 struct hci_conn *conn;
2863 int err;
2864
2865 BT_DBG("");
2866
Johan Hedberg28424702012-02-02 04:02:29 +02002867 hci_dev_lock(hdev);
2868
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002869 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002870 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2871 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002872 goto unlock;
2873 }
2874
Johan Hedberg333ae952015-03-17 13:48:47 +02002875 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002876 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002877 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2878 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002879 goto unlock;
2880 }
2881
2882 conn = cmd->user_data;
2883
2884 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002885 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2886 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002887 goto unlock;
2888 }
2889
Johan Hedberga511b352014-12-11 21:45:45 +02002890 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2891 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002892
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002893 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2894 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002895unlock:
2896 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002897 return err;
2898}
2899
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002900static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002901 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002902 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002903{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002904 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002905 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002906 int err;
2907
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002908 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002909
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002910 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002911 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2912 MGMT_STATUS_NOT_POWERED, addr,
2913 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002914 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002915 }
2916
Johan Hedberg1707c602013-03-15 17:07:15 -05002917 if (addr->type == BDADDR_BREDR)
2918 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002919 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002920 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2921 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002922
Johan Hedberg272d90d2012-02-09 15:26:12 +02002923 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002924 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2925 MGMT_STATUS_NOT_CONNECTED, addr,
2926 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002927 goto done;
2928 }
2929
Johan Hedberg1707c602013-03-15 17:07:15 -05002930 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002931 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002932 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002933 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2934 MGMT_STATUS_SUCCESS, addr,
2935 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002936 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002937 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2938 MGMT_STATUS_FAILED, addr,
2939 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002940
Brian Gix47c15e22011-11-16 13:53:14 -08002941 goto done;
2942 }
2943
Johan Hedberg1707c602013-03-15 17:07:15 -05002944 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002945 if (!cmd) {
2946 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002947 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002948 }
2949
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002950 cmd->cmd_complete = addr_cmd_complete;
2951
Brian Gix0df4c182011-11-16 13:53:13 -08002952 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002953 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2954 struct hci_cp_user_passkey_reply cp;
2955
Johan Hedberg1707c602013-03-15 17:07:15 -05002956 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002957 cp.passkey = passkey;
2958 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2959 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002960 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2961 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002962
Johan Hedberga664b5b2011-02-19 12:06:02 -03002963 if (err < 0)
2964 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002965
Brian Gix0df4c182011-11-16 13:53:13 -08002966done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002967 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002968 return err;
2969}
2970
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302971static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2972 void *data, u16 len)
2973{
2974 struct mgmt_cp_pin_code_neg_reply *cp = data;
2975
2976 BT_DBG("");
2977
Johan Hedberg1707c602013-03-15 17:07:15 -05002978 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302979 MGMT_OP_PIN_CODE_NEG_REPLY,
2980 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2981}
2982
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002983static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2984 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002985{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002986 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002987
2988 BT_DBG("");
2989
2990 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002991 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2992 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002993
Johan Hedberg1707c602013-03-15 17:07:15 -05002994 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002995 MGMT_OP_USER_CONFIRM_REPLY,
2996 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002997}
2998
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002999static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003000 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003001{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003002 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003003
3004 BT_DBG("");
3005
Johan Hedberg1707c602013-03-15 17:07:15 -05003006 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003007 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3008 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003009}
3010
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3012 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003013{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003014 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003015
3016 BT_DBG("");
3017
Johan Hedberg1707c602013-03-15 17:07:15 -05003018 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003019 MGMT_OP_USER_PASSKEY_REPLY,
3020 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003021}
3022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003023static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003024 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003025{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003026 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003027
3028 BT_DBG("");
3029
Johan Hedberg1707c602013-03-15 17:07:15 -05003030 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003031 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3032 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003033}
3034
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003035static void adv_expire(struct hci_dev *hdev, u32 flags)
3036{
3037 struct adv_info *adv_instance;
3038 struct hci_request req;
3039 int err;
3040
3041 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3042 if (!adv_instance)
3043 return;
3044
3045 /* stop if current instance doesn't need to be changed */
3046 if (!(adv_instance->flags & flags))
3047 return;
3048
3049 cancel_adv_timeout(hdev);
3050
3051 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3052 if (!adv_instance)
3053 return;
3054
3055 hci_req_init(&req, hdev);
3056 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3057 true);
3058 if (err)
3059 return;
3060
3061 hci_req_run(&req, NULL);
3062}
3063
Marcel Holtmann1904a852015-01-11 13:50:44 -08003064static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003065{
3066 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003067 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003068
3069 BT_DBG("status 0x%02x", status);
3070
3071 hci_dev_lock(hdev);
3072
Johan Hedberg333ae952015-03-17 13:48:47 +02003073 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003074 if (!cmd)
3075 goto unlock;
3076
3077 cp = cmd->param;
3078
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003079 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003080 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3081 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003082 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003083 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3084 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003085
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003086 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3087 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3088 }
3089
Johan Hedberg13928972013-03-15 17:07:00 -05003090 mgmt_pending_remove(cmd);
3091
3092unlock:
3093 hci_dev_unlock(hdev);
3094}
3095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003096static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003097 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003098{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003099 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003100 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003101 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003102 int err;
3103
3104 BT_DBG("");
3105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003106 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003107
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003108 /* If the old values are the same as the new ones just return a
3109 * direct command complete event.
3110 */
3111 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3112 !memcmp(hdev->short_name, cp->short_name,
3113 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003114 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3115 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003116 goto failed;
3117 }
3118
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003119 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003120
Johan Hedbergb5235a62012-02-21 14:32:24 +02003121 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003122 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003123
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003124 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3125 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003126 if (err < 0)
3127 goto failed;
3128
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003129 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3130 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003131 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003132
Johan Hedbergb5235a62012-02-21 14:32:24 +02003133 goto failed;
3134 }
3135
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003136 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003137 if (!cmd) {
3138 err = -ENOMEM;
3139 goto failed;
3140 }
3141
Johan Hedberg13928972013-03-15 17:07:00 -05003142 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3143
Johan Hedberg890ea892013-03-15 17:06:52 -05003144 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003145
3146 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003147 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003148 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003149 }
3150
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003151 /* The name is stored in the scan response data and so
3152 * no need to udpate the advertising data here.
3153 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003154 if (lmp_le_capable(hdev))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003155 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003156
Johan Hedberg13928972013-03-15 17:07:00 -05003157 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003158 if (err < 0)
3159 mgmt_pending_remove(cmd);
3160
3161failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003162 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003163 return err;
3164}
3165
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003166static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3167 u16 len)
3168{
3169 struct mgmt_cp_set_appearance *cp = data;
3170 u16 apperance;
3171 int err;
3172
3173 BT_DBG("");
3174
3175 apperance = le16_to_cpu(cp->appearance);
3176
3177 hci_dev_lock(hdev);
3178
3179 if (hdev->appearance != apperance) {
3180 hdev->appearance = apperance;
3181
3182 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3183 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
3184 }
3185
3186 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3187 0);
3188
3189 hci_dev_unlock(hdev);
3190
3191 return err;
3192}
3193
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003194static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3195 u16 opcode, struct sk_buff *skb)
3196{
3197 struct mgmt_rp_read_local_oob_data mgmt_rp;
3198 size_t rp_size = sizeof(mgmt_rp);
3199 struct mgmt_pending_cmd *cmd;
3200
3201 BT_DBG("%s status %u", hdev->name, status);
3202
3203 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3204 if (!cmd)
3205 return;
3206
3207 if (status || !skb) {
3208 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3209 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3210 goto remove;
3211 }
3212
3213 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3214
3215 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3216 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3217
3218 if (skb->len < sizeof(*rp)) {
3219 mgmt_cmd_status(cmd->sk, hdev->id,
3220 MGMT_OP_READ_LOCAL_OOB_DATA,
3221 MGMT_STATUS_FAILED);
3222 goto remove;
3223 }
3224
3225 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3226 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3227
3228 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3229 } else {
3230 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3231
3232 if (skb->len < sizeof(*rp)) {
3233 mgmt_cmd_status(cmd->sk, hdev->id,
3234 MGMT_OP_READ_LOCAL_OOB_DATA,
3235 MGMT_STATUS_FAILED);
3236 goto remove;
3237 }
3238
3239 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3240 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3241
3242 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3243 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3244 }
3245
3246 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3247 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3248
3249remove:
3250 mgmt_pending_remove(cmd);
3251}
3252
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003253static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003254 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003255{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003256 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003257 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003258 int err;
3259
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003260 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003262 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003263
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003264 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003265 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3266 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003267 goto unlock;
3268 }
3269
Andre Guedes9a1a1992012-07-24 15:03:48 -03003270 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003271 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3272 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003273 goto unlock;
3274 }
3275
Johan Hedberg333ae952015-03-17 13:48:47 +02003276 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003277 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3278 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003279 goto unlock;
3280 }
3281
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003282 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003283 if (!cmd) {
3284 err = -ENOMEM;
3285 goto unlock;
3286 }
3287
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003288 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003289
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003290 if (bredr_sc_enabled(hdev))
3291 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3292 else
3293 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3294
3295 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003296 if (err < 0)
3297 mgmt_pending_remove(cmd);
3298
3299unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003300 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003301 return err;
3302}
3303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003304static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003305 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003306{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003307 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003308 int err;
3309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003310 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003311
Johan Hedberg5d57e792015-01-23 10:10:38 +02003312 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003313 return mgmt_cmd_complete(sk, hdev->id,
3314 MGMT_OP_ADD_REMOTE_OOB_DATA,
3315 MGMT_STATUS_INVALID_PARAMS,
3316 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003317
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003318 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003319
Marcel Holtmannec109112014-01-10 02:07:30 -08003320 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3321 struct mgmt_cp_add_remote_oob_data *cp = data;
3322 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003323
Johan Hedbergc19a4952014-11-17 20:52:19 +02003324 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003325 err = mgmt_cmd_complete(sk, hdev->id,
3326 MGMT_OP_ADD_REMOTE_OOB_DATA,
3327 MGMT_STATUS_INVALID_PARAMS,
3328 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003329 goto unlock;
3330 }
3331
Marcel Holtmannec109112014-01-10 02:07:30 -08003332 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003333 cp->addr.type, cp->hash,
3334 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003335 if (err < 0)
3336 status = MGMT_STATUS_FAILED;
3337 else
3338 status = MGMT_STATUS_SUCCESS;
3339
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003340 err = mgmt_cmd_complete(sk, hdev->id,
3341 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3342 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003343 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3344 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003345 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003346 u8 status;
3347
Johan Hedberg86df9202014-10-26 20:52:27 +01003348 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003349 /* Enforce zero-valued 192-bit parameters as
3350 * long as legacy SMP OOB isn't implemented.
3351 */
3352 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3353 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003354 err = mgmt_cmd_complete(sk, hdev->id,
3355 MGMT_OP_ADD_REMOTE_OOB_DATA,
3356 MGMT_STATUS_INVALID_PARAMS,
3357 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003358 goto unlock;
3359 }
3360
Johan Hedberg86df9202014-10-26 20:52:27 +01003361 rand192 = NULL;
3362 hash192 = NULL;
3363 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003364 /* In case one of the P-192 values is set to zero,
3365 * then just disable OOB data for P-192.
3366 */
3367 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3368 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3369 rand192 = NULL;
3370 hash192 = NULL;
3371 } else {
3372 rand192 = cp->rand192;
3373 hash192 = cp->hash192;
3374 }
3375 }
3376
3377 /* In case one of the P-256 values is set to zero, then just
3378 * disable OOB data for P-256.
3379 */
3380 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3381 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3382 rand256 = NULL;
3383 hash256 = NULL;
3384 } else {
3385 rand256 = cp->rand256;
3386 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003387 }
3388
Johan Hedberg81328d52014-10-26 20:33:47 +01003389 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003390 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003391 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003392 if (err < 0)
3393 status = MGMT_STATUS_FAILED;
3394 else
3395 status = MGMT_STATUS_SUCCESS;
3396
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003397 err = mgmt_cmd_complete(sk, hdev->id,
3398 MGMT_OP_ADD_REMOTE_OOB_DATA,
3399 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003400 } else {
3401 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003402 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3403 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003404 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003405
Johan Hedbergc19a4952014-11-17 20:52:19 +02003406unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003407 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003408 return err;
3409}
3410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003411static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003412 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003413{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003414 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003415 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003416 int err;
3417
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003418 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003419
Johan Hedbergc19a4952014-11-17 20:52:19 +02003420 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003421 return mgmt_cmd_complete(sk, hdev->id,
3422 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3423 MGMT_STATUS_INVALID_PARAMS,
3424 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003425
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003426 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003427
Johan Hedbergeedbd582014-11-15 09:34:23 +02003428 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3429 hci_remote_oob_data_clear(hdev);
3430 status = MGMT_STATUS_SUCCESS;
3431 goto done;
3432 }
3433
Johan Hedberg6928a922014-10-26 20:46:09 +01003434 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003435 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003436 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003437 else
Szymon Janca6785be2012-12-13 15:11:21 +01003438 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003439
Johan Hedbergeedbd582014-11-15 09:34:23 +02003440done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003441 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3442 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003443
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003444 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003445 return err;
3446}
3447
Johan Hedberge68f0722015-11-11 08:30:30 +02003448void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003449{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003450 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003451
Andre Guedes7c307722013-04-30 15:29:28 -03003452 BT_DBG("status %d", status);
3453
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003454 hci_dev_lock(hdev);
3455
Johan Hedberg333ae952015-03-17 13:48:47 +02003456 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003457 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003458 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003459
Johan Hedberg78b781c2016-01-05 13:19:32 +02003460 if (!cmd)
3461 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3462
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003463 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003464 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003465 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003466 }
3467
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003468 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003469}
3470
Johan Hedberg591752a2015-11-11 08:11:24 +02003471static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3472 uint8_t *mgmt_status)
3473{
3474 switch (type) {
3475 case DISCOV_TYPE_LE:
3476 *mgmt_status = mgmt_le_support(hdev);
3477 if (*mgmt_status)
3478 return false;
3479 break;
3480 case DISCOV_TYPE_INTERLEAVED:
3481 *mgmt_status = mgmt_le_support(hdev);
3482 if (*mgmt_status)
3483 return false;
3484 /* Intentional fall-through */
3485 case DISCOV_TYPE_BREDR:
3486 *mgmt_status = mgmt_bredr_support(hdev);
3487 if (*mgmt_status)
3488 return false;
3489 break;
3490 default:
3491 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3492 return false;
3493 }
3494
3495 return true;
3496}
3497
Johan Hedberg78b781c2016-01-05 13:19:32 +02003498static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3499 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003500{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003501 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003502 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003503 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003504 int err;
3505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003506 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003507
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003508 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003509
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003510 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003511 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003512 MGMT_STATUS_NOT_POWERED,
3513 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003514 goto failed;
3515 }
3516
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003517 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003518 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003519 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3520 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003521 goto failed;
3522 }
3523
Johan Hedberg591752a2015-11-11 08:11:24 +02003524 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003525 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3526 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003527 goto failed;
3528 }
3529
Marcel Holtmann22078802014-12-05 11:45:22 +01003530 /* Clear the discovery filter first to free any previously
3531 * allocated memory for the UUID list.
3532 */
3533 hci_discovery_filter_clear(hdev);
3534
Andre Guedes4aab14e2012-02-17 20:39:36 -03003535 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003536 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003537 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3538 hdev->discovery.limited = true;
3539 else
3540 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003541
Johan Hedberg78b781c2016-01-05 13:19:32 +02003542 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003543 if (!cmd) {
3544 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003545 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003546 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003547
Johan Hedberge68f0722015-11-11 08:30:30 +02003548 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003549
3550 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003551 queue_work(hdev->req_workqueue, &hdev->discov_update);
3552 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003553
3554failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003555 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003556 return err;
3557}
3558
Johan Hedberg78b781c2016-01-05 13:19:32 +02003559static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3560 void *data, u16 len)
3561{
3562 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3563 data, len);
3564}
3565
3566static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3567 void *data, u16 len)
3568{
3569 return start_discovery_internal(sk, hdev,
3570 MGMT_OP_START_LIMITED_DISCOVERY,
3571 data, len);
3572}
3573
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003574static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3575 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003576{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003577 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3578 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003579}
3580
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003581static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3582 void *data, u16 len)
3583{
3584 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003585 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003586 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3587 u16 uuid_count, expected_len;
3588 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003589 int err;
3590
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003591 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003592
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003593 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003594
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003595 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003596 err = mgmt_cmd_complete(sk, hdev->id,
3597 MGMT_OP_START_SERVICE_DISCOVERY,
3598 MGMT_STATUS_NOT_POWERED,
3599 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003600 goto failed;
3601 }
3602
3603 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003604 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003605 err = mgmt_cmd_complete(sk, hdev->id,
3606 MGMT_OP_START_SERVICE_DISCOVERY,
3607 MGMT_STATUS_BUSY, &cp->type,
3608 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003609 goto failed;
3610 }
3611
3612 uuid_count = __le16_to_cpu(cp->uuid_count);
3613 if (uuid_count > max_uuid_count) {
3614 BT_ERR("service_discovery: too big uuid_count value %u",
3615 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003616 err = mgmt_cmd_complete(sk, hdev->id,
3617 MGMT_OP_START_SERVICE_DISCOVERY,
3618 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3619 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003620 goto failed;
3621 }
3622
3623 expected_len = sizeof(*cp) + uuid_count * 16;
3624 if (expected_len != len) {
3625 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3626 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003627 err = mgmt_cmd_complete(sk, hdev->id,
3628 MGMT_OP_START_SERVICE_DISCOVERY,
3629 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3630 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003631 goto failed;
3632 }
3633
Johan Hedberg591752a2015-11-11 08:11:24 +02003634 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3635 err = mgmt_cmd_complete(sk, hdev->id,
3636 MGMT_OP_START_SERVICE_DISCOVERY,
3637 status, &cp->type, sizeof(cp->type));
3638 goto failed;
3639 }
3640
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003641 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003642 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003643 if (!cmd) {
3644 err = -ENOMEM;
3645 goto failed;
3646 }
3647
Johan Hedberg2922a942014-12-05 13:36:06 +02003648 cmd->cmd_complete = service_discovery_cmd_complete;
3649
Marcel Holtmann22078802014-12-05 11:45:22 +01003650 /* Clear the discovery filter first to free any previously
3651 * allocated memory for the UUID list.
3652 */
3653 hci_discovery_filter_clear(hdev);
3654
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003655 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003656 hdev->discovery.type = cp->type;
3657 hdev->discovery.rssi = cp->rssi;
3658 hdev->discovery.uuid_count = uuid_count;
3659
3660 if (uuid_count > 0) {
3661 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3662 GFP_KERNEL);
3663 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003664 err = mgmt_cmd_complete(sk, hdev->id,
3665 MGMT_OP_START_SERVICE_DISCOVERY,
3666 MGMT_STATUS_FAILED,
3667 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003668 mgmt_pending_remove(cmd);
3669 goto failed;
3670 }
3671 }
3672
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003673 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003674 queue_work(hdev->req_workqueue, &hdev->discov_update);
3675 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003676
3677failed:
3678 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003679 return err;
3680}
3681
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003682void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003683{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003684 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003685
Andre Guedes0e05bba2013-04-30 15:29:33 -03003686 BT_DBG("status %d", status);
3687
3688 hci_dev_lock(hdev);
3689
Johan Hedberg333ae952015-03-17 13:48:47 +02003690 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003691 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003692 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003693 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003694 }
3695
Andre Guedes0e05bba2013-04-30 15:29:33 -03003696 hci_dev_unlock(hdev);
3697}
3698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003699static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003700 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003701{
Johan Hedbergd9306502012-02-20 23:25:18 +02003702 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003703 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003704 int err;
3705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003706 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003707
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003708 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003709
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003710 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003711 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3712 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3713 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003714 goto unlock;
3715 }
3716
3717 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003718 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3719 MGMT_STATUS_INVALID_PARAMS,
3720 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003721 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003722 }
3723
Johan Hedberg2922a942014-12-05 13:36:06 +02003724 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003725 if (!cmd) {
3726 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003727 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003728 }
3729
Johan Hedberg2922a942014-12-05 13:36:06 +02003730 cmd->cmd_complete = generic_cmd_complete;
3731
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003732 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3733 queue_work(hdev->req_workqueue, &hdev->discov_update);
3734 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003735
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003736unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003737 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003738 return err;
3739}
3740
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003741static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003742 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003743{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003744 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003745 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003746 int err;
3747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003748 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003749
Johan Hedberg561aafb2012-01-04 13:31:59 +02003750 hci_dev_lock(hdev);
3751
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003752 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003753 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3754 MGMT_STATUS_FAILED, &cp->addr,
3755 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003756 goto failed;
3757 }
3758
Johan Hedberga198e7b2012-02-17 14:27:06 +02003759 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003760 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003761 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3762 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3763 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003764 goto failed;
3765 }
3766
3767 if (cp->name_known) {
3768 e->name_state = NAME_KNOWN;
3769 list_del(&e->list);
3770 } else {
3771 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003772 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003773 }
3774
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003775 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3776 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003777
3778failed:
3779 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003780 return err;
3781}
3782
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003783static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003784 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003785{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003786 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003787 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003788 int err;
3789
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003790 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003791
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003792 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003793 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3794 MGMT_STATUS_INVALID_PARAMS,
3795 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003797 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003798
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003799 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3800 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003801 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003802 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003803 goto done;
3804 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003805
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003806 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3807 sk);
3808 status = MGMT_STATUS_SUCCESS;
3809
3810done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003811 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3812 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003813
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003814 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003815
3816 return err;
3817}
3818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003819static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003820 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003821{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003822 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003823 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003824 int err;
3825
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003826 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003827
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003828 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003829 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3830 MGMT_STATUS_INVALID_PARAMS,
3831 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003832
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003833 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003834
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003835 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3836 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003837 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003838 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003839 goto done;
3840 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003841
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003842 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3843 sk);
3844 status = MGMT_STATUS_SUCCESS;
3845
3846done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003847 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3848 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003849
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003850 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003851
3852 return err;
3853}
3854
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003855static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3856 u16 len)
3857{
3858 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003859 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003860 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003861 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003862
3863 BT_DBG("%s", hdev->name);
3864
Szymon Jancc72d4b82012-03-16 16:02:57 +01003865 source = __le16_to_cpu(cp->source);
3866
3867 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003868 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3869 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003870
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003871 hci_dev_lock(hdev);
3872
Szymon Jancc72d4b82012-03-16 16:02:57 +01003873 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003874 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3875 hdev->devid_product = __le16_to_cpu(cp->product);
3876 hdev->devid_version = __le16_to_cpu(cp->version);
3877
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003878 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3879 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003880
Johan Hedberg890ea892013-03-15 17:06:52 -05003881 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003882 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003883 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003884
3885 hci_dev_unlock(hdev);
3886
3887 return err;
3888}
3889
Arman Uguray24b4f382015-03-23 15:57:12 -07003890static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3891 u16 opcode)
3892{
3893 BT_DBG("status %d", status);
3894}
3895
Marcel Holtmann1904a852015-01-11 13:50:44 -08003896static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3897 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003898{
3899 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003900 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003901 u8 instance;
3902 struct adv_info *adv_instance;
3903 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003904
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303905 hci_dev_lock(hdev);
3906
Johan Hedberg4375f102013-09-25 13:26:10 +03003907 if (status) {
3908 u8 mgmt_err = mgmt_status(status);
3909
3910 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3911 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303912 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003913 }
3914
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003915 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003916 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003917 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003918 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003919
Johan Hedberg4375f102013-09-25 13:26:10 +03003920 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3921 &match);
3922
3923 new_settings(hdev, match.sk);
3924
3925 if (match.sk)
3926 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303927
Arman Uguray24b4f382015-03-23 15:57:12 -07003928 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003929 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003930 */
3931 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003932 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003933 goto unlock;
3934
Florian Grandel7816b822015-06-18 03:16:45 +02003935 instance = hdev->cur_adv_instance;
3936 if (!instance) {
3937 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3938 struct adv_info, list);
3939 if (!adv_instance)
3940 goto unlock;
3941
3942 instance = adv_instance->instance;
3943 }
3944
Arman Uguray24b4f382015-03-23 15:57:12 -07003945 hci_req_init(&req, hdev);
3946
Johan Hedbergf2252572015-11-18 12:49:20 +02003947 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003948
Florian Grandel7816b822015-06-18 03:16:45 +02003949 if (!err)
3950 err = hci_req_run(&req, enable_advertising_instance);
3951
3952 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003953 BT_ERR("Failed to re-configure advertising");
3954
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303955unlock:
3956 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003957}
3958
Marcel Holtmann21b51872013-10-10 09:47:53 -07003959static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3960 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003961{
3962 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003963 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003964 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003965 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003966 int err;
3967
3968 BT_DBG("request for %s", hdev->name);
3969
Johan Hedberge6fe7982013-10-02 15:45:22 +03003970 status = mgmt_le_support(hdev);
3971 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003972 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3973 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003974
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003975 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003976 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3977 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003978
3979 hci_dev_lock(hdev);
3980
3981 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003982
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003983 /* The following conditions are ones which mean that we should
3984 * not do any HCI communication but directly send a mgmt
3985 * response to user space (after toggling the flag if
3986 * necessary).
3987 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003988 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003989 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3990 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003991 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003992 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003993 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003994 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003995
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003996 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003997 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07003998 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003999 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004000 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004001 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004002 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004003 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004004 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004005 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004006 }
4007
4008 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4009 if (err < 0)
4010 goto unlock;
4011
4012 if (changed)
4013 err = new_settings(hdev, sk);
4014
4015 goto unlock;
4016 }
4017
Johan Hedberg333ae952015-03-17 13:48:47 +02004018 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4019 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004020 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4021 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004022 goto unlock;
4023 }
4024
4025 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4026 if (!cmd) {
4027 err = -ENOMEM;
4028 goto unlock;
4029 }
4030
4031 hci_req_init(&req, hdev);
4032
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004033 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004034 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004035 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004036 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004037
Florian Grandel7816b822015-06-18 03:16:45 +02004038 cancel_adv_timeout(hdev);
4039
Arman Uguray24b4f382015-03-23 15:57:12 -07004040 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004041 /* Switch to instance "0" for the Set Advertising setting.
4042 * We cannot use update_[adv|scan_rsp]_data() here as the
4043 * HCI_ADVERTISING flag is not yet set.
4044 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004045 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02004046 __hci_req_update_adv_data(&req, 0x00);
4047 __hci_req_update_scan_rsp_data(&req, 0x00);
4048 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004049 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004050 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004051 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004052
4053 err = hci_req_run(&req, set_advertising_complete);
4054 if (err < 0)
4055 mgmt_pending_remove(cmd);
4056
4057unlock:
4058 hci_dev_unlock(hdev);
4059 return err;
4060}
4061
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004062static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4063 void *data, u16 len)
4064{
4065 struct mgmt_cp_set_static_address *cp = data;
4066 int err;
4067
4068 BT_DBG("%s", hdev->name);
4069
Marcel Holtmann62af4442013-10-02 22:10:32 -07004070 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004071 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4072 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004073
4074 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004075 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4076 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004077
4078 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4079 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004080 return mgmt_cmd_status(sk, hdev->id,
4081 MGMT_OP_SET_STATIC_ADDRESS,
4082 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004083
4084 /* Two most significant bits shall be set */
4085 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004086 return mgmt_cmd_status(sk, hdev->id,
4087 MGMT_OP_SET_STATIC_ADDRESS,
4088 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004089 }
4090
4091 hci_dev_lock(hdev);
4092
4093 bacpy(&hdev->static_addr, &cp->bdaddr);
4094
Marcel Holtmann93690c22015-03-06 10:11:21 -08004095 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4096 if (err < 0)
4097 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004098
Marcel Holtmann93690c22015-03-06 10:11:21 -08004099 err = new_settings(hdev, sk);
4100
4101unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004102 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004103 return err;
4104}
4105
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004106static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4107 void *data, u16 len)
4108{
4109 struct mgmt_cp_set_scan_params *cp = data;
4110 __u16 interval, window;
4111 int err;
4112
4113 BT_DBG("%s", hdev->name);
4114
4115 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004116 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4117 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004118
4119 interval = __le16_to_cpu(cp->interval);
4120
4121 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004122 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4123 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004124
4125 window = __le16_to_cpu(cp->window);
4126
4127 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004128 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4129 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004130
Marcel Holtmann899e1072013-10-14 09:55:32 -07004131 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004132 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4133 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004134
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004135 hci_dev_lock(hdev);
4136
4137 hdev->le_scan_interval = interval;
4138 hdev->le_scan_window = window;
4139
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004140 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4141 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004142
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004143 /* If background scan is running, restart it so new parameters are
4144 * loaded.
4145 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004146 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004147 hdev->discovery.state == DISCOVERY_STOPPED) {
4148 struct hci_request req;
4149
4150 hci_req_init(&req, hdev);
4151
4152 hci_req_add_le_scan_disable(&req);
4153 hci_req_add_le_passive_scan(&req);
4154
4155 hci_req_run(&req, NULL);
4156 }
4157
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004158 hci_dev_unlock(hdev);
4159
4160 return err;
4161}
4162
Marcel Holtmann1904a852015-01-11 13:50:44 -08004163static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4164 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004165{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004166 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004167
4168 BT_DBG("status 0x%02x", status);
4169
4170 hci_dev_lock(hdev);
4171
Johan Hedberg333ae952015-03-17 13:48:47 +02004172 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004173 if (!cmd)
4174 goto unlock;
4175
4176 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004177 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4178 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004179 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004180 struct mgmt_mode *cp = cmd->param;
4181
4182 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004183 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004184 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004185 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004186
Johan Hedberg33e38b32013-03-15 17:07:05 -05004187 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4188 new_settings(hdev, cmd->sk);
4189 }
4190
4191 mgmt_pending_remove(cmd);
4192
4193unlock:
4194 hci_dev_unlock(hdev);
4195}
4196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004197static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004198 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004199{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004200 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004201 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004202 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004203 int err;
4204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004205 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004206
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004207 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004208 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004209 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4210 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004211
Johan Hedberga7e80f22013-01-09 16:05:19 +02004212 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004213 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4214 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004215
Antti Julkuf6422ec2011-06-22 13:11:56 +03004216 hci_dev_lock(hdev);
4217
Johan Hedberg333ae952015-03-17 13:48:47 +02004218 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004219 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4220 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004221 goto unlock;
4222 }
4223
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004224 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004225 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4226 hdev);
4227 goto unlock;
4228 }
4229
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004230 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004231 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004232 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4233 hdev);
4234 new_settings(hdev, sk);
4235 goto unlock;
4236 }
4237
Johan Hedberg33e38b32013-03-15 17:07:05 -05004238 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4239 data, len);
4240 if (!cmd) {
4241 err = -ENOMEM;
4242 goto unlock;
4243 }
4244
4245 hci_req_init(&req, hdev);
4246
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004247 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004248
4249 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004250 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004251 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4252 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004253 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004254 }
4255
Johan Hedberg33e38b32013-03-15 17:07:05 -05004256unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004257 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004258
Antti Julkuf6422ec2011-06-22 13:11:56 +03004259 return err;
4260}
4261
Marcel Holtmann1904a852015-01-11 13:50:44 -08004262static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004263{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004264 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004265
4266 BT_DBG("status 0x%02x", status);
4267
4268 hci_dev_lock(hdev);
4269
Johan Hedberg333ae952015-03-17 13:48:47 +02004270 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004271 if (!cmd)
4272 goto unlock;
4273
4274 if (status) {
4275 u8 mgmt_err = mgmt_status(status);
4276
4277 /* We need to restore the flag if related HCI commands
4278 * failed.
4279 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004280 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004281
Johan Hedberga69e8372015-03-06 21:08:53 +02004282 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004283 } else {
4284 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4285 new_settings(hdev, cmd->sk);
4286 }
4287
4288 mgmt_pending_remove(cmd);
4289
4290unlock:
4291 hci_dev_unlock(hdev);
4292}
4293
4294static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4295{
4296 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004297 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004298 struct hci_request req;
4299 int err;
4300
4301 BT_DBG("request for %s", hdev->name);
4302
4303 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004304 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4305 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004306
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004307 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004308 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4309 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004310
4311 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004312 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4313 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004314
4315 hci_dev_lock(hdev);
4316
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004317 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004318 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4319 goto unlock;
4320 }
4321
4322 if (!hdev_is_powered(hdev)) {
4323 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004324 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4325 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4326 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4327 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4328 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004329 }
4330
Marcel Holtmannce05d602015-03-13 02:11:03 -07004331 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004332
4333 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4334 if (err < 0)
4335 goto unlock;
4336
4337 err = new_settings(hdev, sk);
4338 goto unlock;
4339 }
4340
4341 /* Reject disabling when powered on */
4342 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004343 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4344 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004345 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004346 } else {
4347 /* When configuring a dual-mode controller to operate
4348 * with LE only and using a static address, then switching
4349 * BR/EDR back on is not allowed.
4350 *
4351 * Dual-mode controllers shall operate with the public
4352 * address as its identity address for BR/EDR and LE. So
4353 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004354 *
4355 * The same restrictions applies when secure connections
4356 * has been enabled. For BR/EDR this is a controller feature
4357 * while for LE it is a host stack feature. This means that
4358 * switching BR/EDR back on when secure connections has been
4359 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004360 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004361 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004362 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004363 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004364 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4365 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004366 goto unlock;
4367 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004368 }
4369
Johan Hedberg333ae952015-03-17 13:48:47 +02004370 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004371 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4372 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004373 goto unlock;
4374 }
4375
4376 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4377 if (!cmd) {
4378 err = -ENOMEM;
4379 goto unlock;
4380 }
4381
Johan Hedbergf2252572015-11-18 12:49:20 +02004382 /* We need to flip the bit already here so that
4383 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004384 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004385 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004386
4387 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004388
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004389 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004390 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004391
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004392 /* Since only the advertising data flags will change, there
4393 * is no need to update the scan response data.
4394 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004395 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004396
Johan Hedberg0663ca22013-10-02 13:43:14 +03004397 err = hci_req_run(&req, set_bredr_complete);
4398 if (err < 0)
4399 mgmt_pending_remove(cmd);
4400
4401unlock:
4402 hci_dev_unlock(hdev);
4403 return err;
4404}
4405
Johan Hedberga1443f52015-01-23 15:42:46 +02004406static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4407{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004408 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004409 struct mgmt_mode *cp;
4410
4411 BT_DBG("%s status %u", hdev->name, status);
4412
4413 hci_dev_lock(hdev);
4414
Johan Hedberg333ae952015-03-17 13:48:47 +02004415 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004416 if (!cmd)
4417 goto unlock;
4418
4419 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004420 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4421 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004422 goto remove;
4423 }
4424
4425 cp = cmd->param;
4426
4427 switch (cp->val) {
4428 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004429 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4430 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004431 break;
4432 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004433 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004434 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004435 break;
4436 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004437 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4438 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004439 break;
4440 }
4441
4442 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4443 new_settings(hdev, cmd->sk);
4444
4445remove:
4446 mgmt_pending_remove(cmd);
4447unlock:
4448 hci_dev_unlock(hdev);
4449}
4450
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004451static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4452 void *data, u16 len)
4453{
4454 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004455 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004456 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004457 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004458 int err;
4459
4460 BT_DBG("request for %s", hdev->name);
4461
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004462 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004463 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004464 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4465 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004466
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004467 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004468 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004469 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004470 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4471 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004472
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004473 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004474 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004475 MGMT_STATUS_INVALID_PARAMS);
4476
4477 hci_dev_lock(hdev);
4478
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004479 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004480 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004481 bool changed;
4482
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004483 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004484 changed = !hci_dev_test_and_set_flag(hdev,
4485 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004486 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004487 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004488 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004489 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004490 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004491 changed = hci_dev_test_and_clear_flag(hdev,
4492 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004493 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004494 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004495
4496 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4497 if (err < 0)
4498 goto failed;
4499
4500 if (changed)
4501 err = new_settings(hdev, sk);
4502
4503 goto failed;
4504 }
4505
Johan Hedberg333ae952015-03-17 13:48:47 +02004506 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004507 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4508 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004509 goto failed;
4510 }
4511
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004512 val = !!cp->val;
4513
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004514 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4515 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004516 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4517 goto failed;
4518 }
4519
4520 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4521 if (!cmd) {
4522 err = -ENOMEM;
4523 goto failed;
4524 }
4525
Johan Hedberga1443f52015-01-23 15:42:46 +02004526 hci_req_init(&req, hdev);
4527 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4528 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004529 if (err < 0) {
4530 mgmt_pending_remove(cmd);
4531 goto failed;
4532 }
4533
4534failed:
4535 hci_dev_unlock(hdev);
4536 return err;
4537}
4538
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004539static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4540 void *data, u16 len)
4541{
4542 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004543 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004544 int err;
4545
4546 BT_DBG("request for %s", hdev->name);
4547
Johan Hedbergb97109792014-06-24 14:00:28 +03004548 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004549 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4550 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004551
4552 hci_dev_lock(hdev);
4553
4554 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004555 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004556 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004557 changed = hci_dev_test_and_clear_flag(hdev,
4558 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004559
Johan Hedbergb97109792014-06-24 14:00:28 +03004560 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004561 use_changed = !hci_dev_test_and_set_flag(hdev,
4562 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004563 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004564 use_changed = hci_dev_test_and_clear_flag(hdev,
4565 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004566
4567 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004568 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004569 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4570 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4571 sizeof(mode), &mode);
4572 }
4573
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004574 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4575 if (err < 0)
4576 goto unlock;
4577
4578 if (changed)
4579 err = new_settings(hdev, sk);
4580
4581unlock:
4582 hci_dev_unlock(hdev);
4583 return err;
4584}
4585
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004586static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4587 u16 len)
4588{
4589 struct mgmt_cp_set_privacy *cp = cp_data;
4590 bool changed;
4591 int err;
4592
4593 BT_DBG("request for %s", hdev->name);
4594
4595 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004596 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4597 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004598
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004599 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004600 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4601 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004602
4603 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004604 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4605 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004606
4607 hci_dev_lock(hdev);
4608
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004609 /* If user space supports this command it is also expected to
4610 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4611 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004612 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004613
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004614 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004615 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004616 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004617 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004618 if (cp->privacy == 0x02)
4619 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4620 else
4621 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004622 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004623 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004624 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004625 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004626 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004627 }
4628
4629 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4630 if (err < 0)
4631 goto unlock;
4632
4633 if (changed)
4634 err = new_settings(hdev, sk);
4635
4636unlock:
4637 hci_dev_unlock(hdev);
4638 return err;
4639}
4640
Johan Hedberg41edf162014-02-18 10:19:35 +02004641static bool irk_is_valid(struct mgmt_irk_info *irk)
4642{
4643 switch (irk->addr.type) {
4644 case BDADDR_LE_PUBLIC:
4645 return true;
4646
4647 case BDADDR_LE_RANDOM:
4648 /* Two most significant bits shall be set */
4649 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4650 return false;
4651 return true;
4652 }
4653
4654 return false;
4655}
4656
4657static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4658 u16 len)
4659{
4660 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004661 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4662 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004663 u16 irk_count, expected_len;
4664 int i, err;
4665
4666 BT_DBG("request for %s", hdev->name);
4667
4668 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004669 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4670 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004671
4672 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004673 if (irk_count > max_irk_count) {
4674 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004675 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4676 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004677 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004678
4679 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4680 if (expected_len != len) {
4681 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004682 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004683 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4684 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004685 }
4686
4687 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4688
4689 for (i = 0; i < irk_count; i++) {
4690 struct mgmt_irk_info *key = &cp->irks[i];
4691
4692 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004693 return mgmt_cmd_status(sk, hdev->id,
4694 MGMT_OP_LOAD_IRKS,
4695 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004696 }
4697
4698 hci_dev_lock(hdev);
4699
4700 hci_smp_irks_clear(hdev);
4701
4702 for (i = 0; i < irk_count; i++) {
4703 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004704
Johan Hedberg85813a72015-10-21 18:02:59 +03004705 hci_add_irk(hdev, &irk->addr.bdaddr,
4706 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004707 BDADDR_ANY);
4708 }
4709
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004710 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004711
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004712 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004713
4714 hci_dev_unlock(hdev);
4715
4716 return err;
4717}
4718
Johan Hedberg3f706b72013-01-20 14:27:16 +02004719static bool ltk_is_valid(struct mgmt_ltk_info *key)
4720{
4721 if (key->master != 0x00 && key->master != 0x01)
4722 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004723
4724 switch (key->addr.type) {
4725 case BDADDR_LE_PUBLIC:
4726 return true;
4727
4728 case BDADDR_LE_RANDOM:
4729 /* Two most significant bits shall be set */
4730 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4731 return false;
4732 return true;
4733 }
4734
4735 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004736}
4737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004738static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004739 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004740{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004741 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004742 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4743 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004744 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004745 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004746
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004747 BT_DBG("request for %s", hdev->name);
4748
4749 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004750 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4751 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004752
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004753 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004754 if (key_count > max_key_count) {
4755 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004756 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4757 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004758 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004759
4760 expected_len = sizeof(*cp) + key_count *
4761 sizeof(struct mgmt_ltk_info);
4762 if (expected_len != len) {
4763 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004764 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004765 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4766 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004767 }
4768
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004769 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004770
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004771 for (i = 0; i < key_count; i++) {
4772 struct mgmt_ltk_info *key = &cp->keys[i];
4773
Johan Hedberg3f706b72013-01-20 14:27:16 +02004774 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004775 return mgmt_cmd_status(sk, hdev->id,
4776 MGMT_OP_LOAD_LONG_TERM_KEYS,
4777 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004778 }
4779
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004780 hci_dev_lock(hdev);
4781
4782 hci_smp_ltks_clear(hdev);
4783
4784 for (i = 0; i < key_count; i++) {
4785 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004786 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004787
Johan Hedberg61b43352014-05-29 19:36:53 +03004788 switch (key->type) {
4789 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004790 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004791 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004792 break;
4793 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004794 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004795 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004796 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004797 case MGMT_LTK_P256_UNAUTH:
4798 authenticated = 0x00;
4799 type = SMP_LTK_P256;
4800 break;
4801 case MGMT_LTK_P256_AUTH:
4802 authenticated = 0x01;
4803 type = SMP_LTK_P256;
4804 break;
4805 case MGMT_LTK_P256_DEBUG:
4806 authenticated = 0x00;
4807 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004808 default:
4809 continue;
4810 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004811
Johan Hedberg85813a72015-10-21 18:02:59 +03004812 hci_add_ltk(hdev, &key->addr.bdaddr,
4813 le_addr_type(key->addr.type), type, authenticated,
4814 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004815 }
4816
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004817 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004818 NULL, 0);
4819
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004820 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004821
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004822 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004823}
4824
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004825static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004826{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004827 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004828 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004829 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004830
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004831 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004832
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004833 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004834 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004835 rp.tx_power = conn->tx_power;
4836 rp.max_tx_power = conn->max_tx_power;
4837 } else {
4838 rp.rssi = HCI_RSSI_INVALID;
4839 rp.tx_power = HCI_TX_POWER_INVALID;
4840 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004841 }
4842
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004843 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4844 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004845
4846 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004847 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004848
4849 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004850}
4851
Marcel Holtmann1904a852015-01-11 13:50:44 -08004852static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4853 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004854{
4855 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004856 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004857 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004858 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004859 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004860
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004861 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004862
4863 hci_dev_lock(hdev);
4864
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004865 /* Commands sent in request are either Read RSSI or Read Transmit Power
4866 * Level so we check which one was last sent to retrieve connection
4867 * handle. Both commands have handle as first parameter so it's safe to
4868 * cast data on the same command struct.
4869 *
4870 * First command sent is always Read RSSI and we fail only if it fails.
4871 * In other case we simply override error to indicate success as we
4872 * already remembered if TX power value is actually valid.
4873 */
4874 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4875 if (!cp) {
4876 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004877 status = MGMT_STATUS_SUCCESS;
4878 } else {
4879 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004880 }
4881
4882 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004883 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004884 goto unlock;
4885 }
4886
4887 handle = __le16_to_cpu(cp->handle);
4888 conn = hci_conn_hash_lookup_handle(hdev, handle);
4889 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004890 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004891 goto unlock;
4892 }
4893
Johan Hedberg333ae952015-03-17 13:48:47 +02004894 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004895 if (!cmd)
4896 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004897
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004898 cmd->cmd_complete(cmd, status);
4899 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004900
4901unlock:
4902 hci_dev_unlock(hdev);
4903}
4904
4905static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4906 u16 len)
4907{
4908 struct mgmt_cp_get_conn_info *cp = data;
4909 struct mgmt_rp_get_conn_info rp;
4910 struct hci_conn *conn;
4911 unsigned long conn_info_age;
4912 int err = 0;
4913
4914 BT_DBG("%s", hdev->name);
4915
4916 memset(&rp, 0, sizeof(rp));
4917 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4918 rp.addr.type = cp->addr.type;
4919
4920 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004921 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4922 MGMT_STATUS_INVALID_PARAMS,
4923 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004924
4925 hci_dev_lock(hdev);
4926
4927 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004928 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4929 MGMT_STATUS_NOT_POWERED, &rp,
4930 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004931 goto unlock;
4932 }
4933
4934 if (cp->addr.type == BDADDR_BREDR)
4935 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4936 &cp->addr.bdaddr);
4937 else
4938 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4939
4940 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004941 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4942 MGMT_STATUS_NOT_CONNECTED, &rp,
4943 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004944 goto unlock;
4945 }
4946
Johan Hedberg333ae952015-03-17 13:48:47 +02004947 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004948 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4949 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004950 goto unlock;
4951 }
4952
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004953 /* To avoid client trying to guess when to poll again for information we
4954 * calculate conn info age as random value between min/max set in hdev.
4955 */
4956 conn_info_age = hdev->conn_info_min_age +
4957 prandom_u32_max(hdev->conn_info_max_age -
4958 hdev->conn_info_min_age);
4959
4960 /* Query controller to refresh cached values if they are too old or were
4961 * never read.
4962 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004963 if (time_after(jiffies, conn->conn_info_timestamp +
4964 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004965 !conn->conn_info_timestamp) {
4966 struct hci_request req;
4967 struct hci_cp_read_tx_power req_txp_cp;
4968 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004969 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004970
4971 hci_req_init(&req, hdev);
4972 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4973 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4974 &req_rssi_cp);
4975
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004976 /* For LE links TX power does not change thus we don't need to
4977 * query for it once value is known.
4978 */
4979 if (!bdaddr_type_is_le(cp->addr.type) ||
4980 conn->tx_power == HCI_TX_POWER_INVALID) {
4981 req_txp_cp.handle = cpu_to_le16(conn->handle);
4982 req_txp_cp.type = 0x00;
4983 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4984 sizeof(req_txp_cp), &req_txp_cp);
4985 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004986
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004987 /* Max TX power needs to be read only once per connection */
4988 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4989 req_txp_cp.handle = cpu_to_le16(conn->handle);
4990 req_txp_cp.type = 0x01;
4991 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4992 sizeof(req_txp_cp), &req_txp_cp);
4993 }
4994
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004995 err = hci_req_run(&req, conn_info_refresh_complete);
4996 if (err < 0)
4997 goto unlock;
4998
4999 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5000 data, len);
5001 if (!cmd) {
5002 err = -ENOMEM;
5003 goto unlock;
5004 }
5005
5006 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005007 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005008 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005009
5010 conn->conn_info_timestamp = jiffies;
5011 } else {
5012 /* Cache is valid, just reply with values cached in hci_conn */
5013 rp.rssi = conn->rssi;
5014 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005015 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005016
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005017 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5018 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005019 }
5020
5021unlock:
5022 hci_dev_unlock(hdev);
5023 return err;
5024}
5025
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005026static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005027{
5028 struct hci_conn *conn = cmd->user_data;
5029 struct mgmt_rp_get_clock_info rp;
5030 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005031 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005032
5033 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005034 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005035
5036 if (status)
5037 goto complete;
5038
5039 hdev = hci_dev_get(cmd->index);
5040 if (hdev) {
5041 rp.local_clock = cpu_to_le32(hdev->clock);
5042 hci_dev_put(hdev);
5043 }
5044
5045 if (conn) {
5046 rp.piconet_clock = cpu_to_le32(conn->clock);
5047 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5048 }
5049
5050complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005051 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5052 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005053
5054 if (conn) {
5055 hci_conn_drop(conn);
5056 hci_conn_put(conn);
5057 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005058
5059 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005060}
5061
Marcel Holtmann1904a852015-01-11 13:50:44 -08005062static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005063{
Johan Hedberg95868422014-06-28 17:54:07 +03005064 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005065 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005066 struct hci_conn *conn;
5067
5068 BT_DBG("%s status %u", hdev->name, status);
5069
5070 hci_dev_lock(hdev);
5071
5072 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5073 if (!hci_cp)
5074 goto unlock;
5075
5076 if (hci_cp->which) {
5077 u16 handle = __le16_to_cpu(hci_cp->handle);
5078 conn = hci_conn_hash_lookup_handle(hdev, handle);
5079 } else {
5080 conn = NULL;
5081 }
5082
Johan Hedberg333ae952015-03-17 13:48:47 +02005083 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005084 if (!cmd)
5085 goto unlock;
5086
Johan Hedberg69487372014-12-05 13:36:07 +02005087 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005088 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005089
5090unlock:
5091 hci_dev_unlock(hdev);
5092}
5093
5094static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5095 u16 len)
5096{
5097 struct mgmt_cp_get_clock_info *cp = data;
5098 struct mgmt_rp_get_clock_info rp;
5099 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005100 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005101 struct hci_request req;
5102 struct hci_conn *conn;
5103 int err;
5104
5105 BT_DBG("%s", hdev->name);
5106
5107 memset(&rp, 0, sizeof(rp));
5108 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5109 rp.addr.type = cp->addr.type;
5110
5111 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005112 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5113 MGMT_STATUS_INVALID_PARAMS,
5114 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005115
5116 hci_dev_lock(hdev);
5117
5118 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005119 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5120 MGMT_STATUS_NOT_POWERED, &rp,
5121 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005122 goto unlock;
5123 }
5124
5125 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5126 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5127 &cp->addr.bdaddr);
5128 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005129 err = mgmt_cmd_complete(sk, hdev->id,
5130 MGMT_OP_GET_CLOCK_INFO,
5131 MGMT_STATUS_NOT_CONNECTED,
5132 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005133 goto unlock;
5134 }
5135 } else {
5136 conn = NULL;
5137 }
5138
5139 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5140 if (!cmd) {
5141 err = -ENOMEM;
5142 goto unlock;
5143 }
5144
Johan Hedberg69487372014-12-05 13:36:07 +02005145 cmd->cmd_complete = clock_info_cmd_complete;
5146
Johan Hedberg95868422014-06-28 17:54:07 +03005147 hci_req_init(&req, hdev);
5148
5149 memset(&hci_cp, 0, sizeof(hci_cp));
5150 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5151
5152 if (conn) {
5153 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005154 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005155
5156 hci_cp.handle = cpu_to_le16(conn->handle);
5157 hci_cp.which = 0x01; /* Piconet clock */
5158 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5159 }
5160
5161 err = hci_req_run(&req, get_clock_info_complete);
5162 if (err < 0)
5163 mgmt_pending_remove(cmd);
5164
5165unlock:
5166 hci_dev_unlock(hdev);
5167 return err;
5168}
5169
Johan Hedberg5a154e62014-12-19 22:26:02 +02005170static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5171{
5172 struct hci_conn *conn;
5173
5174 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5175 if (!conn)
5176 return false;
5177
5178 if (conn->dst_type != type)
5179 return false;
5180
5181 if (conn->state != BT_CONNECTED)
5182 return false;
5183
5184 return true;
5185}
5186
5187/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005188static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005189 u8 addr_type, u8 auto_connect)
5190{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005191 struct hci_conn_params *params;
5192
5193 params = hci_conn_params_add(hdev, addr, addr_type);
5194 if (!params)
5195 return -EIO;
5196
5197 if (params->auto_connect == auto_connect)
5198 return 0;
5199
5200 list_del_init(&params->action);
5201
5202 switch (auto_connect) {
5203 case HCI_AUTO_CONN_DISABLED:
5204 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005205 /* If auto connect is being disabled when we're trying to
5206 * connect to device, keep connecting.
5207 */
5208 if (params->explicit_connect)
5209 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005210 break;
5211 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005212 if (params->explicit_connect)
5213 list_add(&params->action, &hdev->pend_le_conns);
5214 else
5215 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005216 break;
5217 case HCI_AUTO_CONN_DIRECT:
5218 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005219 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005220 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005221 break;
5222 }
5223
5224 params->auto_connect = auto_connect;
5225
5226 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5227 auto_connect);
5228
5229 return 0;
5230}
5231
Marcel Holtmann8afef092014-06-29 22:28:34 +02005232static void device_added(struct sock *sk, struct hci_dev *hdev,
5233 bdaddr_t *bdaddr, u8 type, u8 action)
5234{
5235 struct mgmt_ev_device_added ev;
5236
5237 bacpy(&ev.addr.bdaddr, bdaddr);
5238 ev.addr.type = type;
5239 ev.action = action;
5240
5241 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5242}
5243
Marcel Holtmann2faade52014-06-29 19:44:03 +02005244static int add_device(struct sock *sk, struct hci_dev *hdev,
5245 void *data, u16 len)
5246{
5247 struct mgmt_cp_add_device *cp = data;
5248 u8 auto_conn, addr_type;
5249 int err;
5250
5251 BT_DBG("%s", hdev->name);
5252
Johan Hedberg66593582014-07-09 12:59:14 +03005253 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005254 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005255 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5256 MGMT_STATUS_INVALID_PARAMS,
5257 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005258
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005259 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005260 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5261 MGMT_STATUS_INVALID_PARAMS,
5262 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005263
5264 hci_dev_lock(hdev);
5265
Johan Hedberg66593582014-07-09 12:59:14 +03005266 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005267 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005268 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005269 err = mgmt_cmd_complete(sk, hdev->id,
5270 MGMT_OP_ADD_DEVICE,
5271 MGMT_STATUS_INVALID_PARAMS,
5272 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005273 goto unlock;
5274 }
5275
5276 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5277 cp->addr.type);
5278 if (err)
5279 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005280
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005281 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005282
Johan Hedberg66593582014-07-09 12:59:14 +03005283 goto added;
5284 }
5285
Johan Hedberg85813a72015-10-21 18:02:59 +03005286 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005287
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005288 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005289 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005290 else if (cp->action == 0x01)
5291 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005292 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005293 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005294
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005295 /* Kernel internally uses conn_params with resolvable private
5296 * address, but Add Device allows only identity addresses.
5297 * Make sure it is enforced before calling
5298 * hci_conn_params_lookup.
5299 */
5300 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005301 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5302 MGMT_STATUS_INVALID_PARAMS,
5303 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005304 goto unlock;
5305 }
5306
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005307 /* If the connection parameters don't exist for this device,
5308 * they will be created and configured with defaults.
5309 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005310 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005311 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005312 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5313 MGMT_STATUS_FAILED, &cp->addr,
5314 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005315 goto unlock;
5316 }
5317
Johan Hedberg51d7a942015-11-11 08:11:18 +02005318 hci_update_background_scan(hdev);
5319
Johan Hedberg66593582014-07-09 12:59:14 +03005320added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005321 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5322
Johan Hedberg51d7a942015-11-11 08:11:18 +02005323 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5324 MGMT_STATUS_SUCCESS, &cp->addr,
5325 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005326
5327unlock:
5328 hci_dev_unlock(hdev);
5329 return err;
5330}
5331
Marcel Holtmann8afef092014-06-29 22:28:34 +02005332static void device_removed(struct sock *sk, struct hci_dev *hdev,
5333 bdaddr_t *bdaddr, u8 type)
5334{
5335 struct mgmt_ev_device_removed ev;
5336
5337 bacpy(&ev.addr.bdaddr, bdaddr);
5338 ev.addr.type = type;
5339
5340 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5341}
5342
Marcel Holtmann2faade52014-06-29 19:44:03 +02005343static int remove_device(struct sock *sk, struct hci_dev *hdev,
5344 void *data, u16 len)
5345{
5346 struct mgmt_cp_remove_device *cp = data;
5347 int err;
5348
5349 BT_DBG("%s", hdev->name);
5350
5351 hci_dev_lock(hdev);
5352
5353 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005354 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005355 u8 addr_type;
5356
Johan Hedberg66593582014-07-09 12:59:14 +03005357 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005358 err = mgmt_cmd_complete(sk, hdev->id,
5359 MGMT_OP_REMOVE_DEVICE,
5360 MGMT_STATUS_INVALID_PARAMS,
5361 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005362 goto unlock;
5363 }
5364
Johan Hedberg66593582014-07-09 12:59:14 +03005365 if (cp->addr.type == BDADDR_BREDR) {
5366 err = hci_bdaddr_list_del(&hdev->whitelist,
5367 &cp->addr.bdaddr,
5368 cp->addr.type);
5369 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005370 err = mgmt_cmd_complete(sk, hdev->id,
5371 MGMT_OP_REMOVE_DEVICE,
5372 MGMT_STATUS_INVALID_PARAMS,
5373 &cp->addr,
5374 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005375 goto unlock;
5376 }
5377
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005378 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005379
Johan Hedberg66593582014-07-09 12:59:14 +03005380 device_removed(sk, hdev, &cp->addr.bdaddr,
5381 cp->addr.type);
5382 goto complete;
5383 }
5384
Johan Hedberg85813a72015-10-21 18:02:59 +03005385 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005386
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005387 /* Kernel internally uses conn_params with resolvable private
5388 * address, but Remove Device allows only identity addresses.
5389 * Make sure it is enforced before calling
5390 * hci_conn_params_lookup.
5391 */
5392 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005393 err = mgmt_cmd_complete(sk, hdev->id,
5394 MGMT_OP_REMOVE_DEVICE,
5395 MGMT_STATUS_INVALID_PARAMS,
5396 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005397 goto unlock;
5398 }
5399
Johan Hedbergc71593d2014-07-02 17:37:28 +03005400 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5401 addr_type);
5402 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005403 err = mgmt_cmd_complete(sk, hdev->id,
5404 MGMT_OP_REMOVE_DEVICE,
5405 MGMT_STATUS_INVALID_PARAMS,
5406 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005407 goto unlock;
5408 }
5409
Johan Hedberg679d2b62015-10-16 10:07:52 +03005410 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5411 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005412 err = mgmt_cmd_complete(sk, hdev->id,
5413 MGMT_OP_REMOVE_DEVICE,
5414 MGMT_STATUS_INVALID_PARAMS,
5415 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005416 goto unlock;
5417 }
5418
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005419 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005420 list_del(&params->list);
5421 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005422 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005423
5424 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005425 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005426 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005427 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005428
Marcel Holtmann2faade52014-06-29 19:44:03 +02005429 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005430 err = mgmt_cmd_complete(sk, hdev->id,
5431 MGMT_OP_REMOVE_DEVICE,
5432 MGMT_STATUS_INVALID_PARAMS,
5433 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005434 goto unlock;
5435 }
5436
Johan Hedberg66593582014-07-09 12:59:14 +03005437 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5438 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5439 list_del(&b->list);
5440 kfree(b);
5441 }
5442
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005443 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005444
Johan Hedberg19de0822014-07-06 13:06:51 +03005445 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5446 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5447 continue;
5448 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005449 if (p->explicit_connect) {
5450 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5451 continue;
5452 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005453 list_del(&p->action);
5454 list_del(&p->list);
5455 kfree(p);
5456 }
5457
5458 BT_DBG("All LE connection parameters were removed");
5459
Johan Hedberg51d7a942015-11-11 08:11:18 +02005460 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005461 }
5462
Johan Hedberg66593582014-07-09 12:59:14 +03005463complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005464 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5465 MGMT_STATUS_SUCCESS, &cp->addr,
5466 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005467unlock:
5468 hci_dev_unlock(hdev);
5469 return err;
5470}
5471
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005472static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5473 u16 len)
5474{
5475 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005476 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5477 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005478 u16 param_count, expected_len;
5479 int i;
5480
5481 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005482 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5483 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005484
5485 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005486 if (param_count > max_param_count) {
5487 BT_ERR("load_conn_param: too big param_count value %u",
5488 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005489 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5490 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005491 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005492
5493 expected_len = sizeof(*cp) + param_count *
5494 sizeof(struct mgmt_conn_param);
5495 if (expected_len != len) {
5496 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5497 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005498 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5499 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005500 }
5501
5502 BT_DBG("%s param_count %u", hdev->name, param_count);
5503
5504 hci_dev_lock(hdev);
5505
5506 hci_conn_params_clear_disabled(hdev);
5507
5508 for (i = 0; i < param_count; i++) {
5509 struct mgmt_conn_param *param = &cp->params[i];
5510 struct hci_conn_params *hci_param;
5511 u16 min, max, latency, timeout;
5512 u8 addr_type;
5513
5514 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5515 param->addr.type);
5516
5517 if (param->addr.type == BDADDR_LE_PUBLIC) {
5518 addr_type = ADDR_LE_DEV_PUBLIC;
5519 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5520 addr_type = ADDR_LE_DEV_RANDOM;
5521 } else {
5522 BT_ERR("Ignoring invalid connection parameters");
5523 continue;
5524 }
5525
5526 min = le16_to_cpu(param->min_interval);
5527 max = le16_to_cpu(param->max_interval);
5528 latency = le16_to_cpu(param->latency);
5529 timeout = le16_to_cpu(param->timeout);
5530
5531 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5532 min, max, latency, timeout);
5533
5534 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5535 BT_ERR("Ignoring invalid connection parameters");
5536 continue;
5537 }
5538
5539 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5540 addr_type);
5541 if (!hci_param) {
5542 BT_ERR("Failed to add connection parameters");
5543 continue;
5544 }
5545
5546 hci_param->conn_min_interval = min;
5547 hci_param->conn_max_interval = max;
5548 hci_param->conn_latency = latency;
5549 hci_param->supervision_timeout = timeout;
5550 }
5551
5552 hci_dev_unlock(hdev);
5553
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005554 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5555 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005556}
5557
Marcel Holtmanndbece372014-07-04 18:11:55 +02005558static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5559 void *data, u16 len)
5560{
5561 struct mgmt_cp_set_external_config *cp = data;
5562 bool changed;
5563 int err;
5564
5565 BT_DBG("%s", hdev->name);
5566
5567 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005568 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5569 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005570
5571 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5573 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005574
5575 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005576 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5577 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005578
5579 hci_dev_lock(hdev);
5580
5581 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005582 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005583 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005584 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005585
5586 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5587 if (err < 0)
5588 goto unlock;
5589
5590 if (!changed)
5591 goto unlock;
5592
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005593 err = new_options(hdev, sk);
5594
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005595 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005596 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005597
Marcel Holtmann516018a2015-03-13 02:11:04 -07005598 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005599 hci_dev_set_flag(hdev, HCI_CONFIG);
5600 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005601
5602 queue_work(hdev->req_workqueue, &hdev->power_on);
5603 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005604 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005605 mgmt_index_added(hdev);
5606 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005607 }
5608
5609unlock:
5610 hci_dev_unlock(hdev);
5611 return err;
5612}
5613
Marcel Holtmann9713c172014-07-06 12:11:15 +02005614static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5615 void *data, u16 len)
5616{
5617 struct mgmt_cp_set_public_address *cp = data;
5618 bool changed;
5619 int err;
5620
5621 BT_DBG("%s", hdev->name);
5622
5623 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005624 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5625 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005626
5627 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005628 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5629 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005630
5631 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005632 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5633 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005634
5635 hci_dev_lock(hdev);
5636
5637 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5638 bacpy(&hdev->public_addr, &cp->bdaddr);
5639
5640 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5641 if (err < 0)
5642 goto unlock;
5643
5644 if (!changed)
5645 goto unlock;
5646
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005647 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005648 err = new_options(hdev, sk);
5649
5650 if (is_configured(hdev)) {
5651 mgmt_index_removed(hdev);
5652
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005653 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005654
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005655 hci_dev_set_flag(hdev, HCI_CONFIG);
5656 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005657
5658 queue_work(hdev->req_workqueue, &hdev->power_on);
5659 }
5660
5661unlock:
5662 hci_dev_unlock(hdev);
5663 return err;
5664}
5665
Johan Hedberg40f66c02015-04-07 21:52:22 +03005666static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5667 u16 opcode, struct sk_buff *skb)
5668{
5669 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5670 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5671 u8 *h192, *r192, *h256, *r256;
5672 struct mgmt_pending_cmd *cmd;
5673 u16 eir_len;
5674 int err;
5675
5676 BT_DBG("%s status %u", hdev->name, status);
5677
5678 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5679 if (!cmd)
5680 return;
5681
5682 mgmt_cp = cmd->param;
5683
5684 if (status) {
5685 status = mgmt_status(status);
5686 eir_len = 0;
5687
5688 h192 = NULL;
5689 r192 = NULL;
5690 h256 = NULL;
5691 r256 = NULL;
5692 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5693 struct hci_rp_read_local_oob_data *rp;
5694
5695 if (skb->len != sizeof(*rp)) {
5696 status = MGMT_STATUS_FAILED;
5697 eir_len = 0;
5698 } else {
5699 status = MGMT_STATUS_SUCCESS;
5700 rp = (void *)skb->data;
5701
5702 eir_len = 5 + 18 + 18;
5703 h192 = rp->hash;
5704 r192 = rp->rand;
5705 h256 = NULL;
5706 r256 = NULL;
5707 }
5708 } else {
5709 struct hci_rp_read_local_oob_ext_data *rp;
5710
5711 if (skb->len != sizeof(*rp)) {
5712 status = MGMT_STATUS_FAILED;
5713 eir_len = 0;
5714 } else {
5715 status = MGMT_STATUS_SUCCESS;
5716 rp = (void *)skb->data;
5717
5718 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5719 eir_len = 5 + 18 + 18;
5720 h192 = NULL;
5721 r192 = NULL;
5722 } else {
5723 eir_len = 5 + 18 + 18 + 18 + 18;
5724 h192 = rp->hash192;
5725 r192 = rp->rand192;
5726 }
5727
5728 h256 = rp->hash256;
5729 r256 = rp->rand256;
5730 }
5731 }
5732
5733 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5734 if (!mgmt_rp)
5735 goto done;
5736
5737 if (status)
5738 goto send_rsp;
5739
5740 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5741 hdev->dev_class, 3);
5742
5743 if (h192 && r192) {
5744 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5745 EIR_SSP_HASH_C192, h192, 16);
5746 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5747 EIR_SSP_RAND_R192, r192, 16);
5748 }
5749
5750 if (h256 && r256) {
5751 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5752 EIR_SSP_HASH_C256, h256, 16);
5753 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5754 EIR_SSP_RAND_R256, r256, 16);
5755 }
5756
5757send_rsp:
5758 mgmt_rp->type = mgmt_cp->type;
5759 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5760
5761 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5762 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5763 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5764 if (err < 0 || status)
5765 goto done;
5766
5767 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5768
5769 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5770 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5771 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5772done:
5773 kfree(mgmt_rp);
5774 mgmt_pending_remove(cmd);
5775}
5776
5777static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5778 struct mgmt_cp_read_local_oob_ext_data *cp)
5779{
5780 struct mgmt_pending_cmd *cmd;
5781 struct hci_request req;
5782 int err;
5783
5784 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5785 cp, sizeof(*cp));
5786 if (!cmd)
5787 return -ENOMEM;
5788
5789 hci_req_init(&req, hdev);
5790
5791 if (bredr_sc_enabled(hdev))
5792 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5793 else
5794 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5795
5796 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5797 if (err < 0) {
5798 mgmt_pending_remove(cmd);
5799 return err;
5800 }
5801
5802 return 0;
5803}
5804
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005805static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5806 void *data, u16 data_len)
5807{
5808 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5809 struct mgmt_rp_read_local_oob_ext_data *rp;
5810 size_t rp_len;
5811 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005812 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005813 int err;
5814
5815 BT_DBG("%s", hdev->name);
5816
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005817 if (hdev_is_powered(hdev)) {
5818 switch (cp->type) {
5819 case BIT(BDADDR_BREDR):
5820 status = mgmt_bredr_support(hdev);
5821 if (status)
5822 eir_len = 0;
5823 else
5824 eir_len = 5;
5825 break;
5826 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5827 status = mgmt_le_support(hdev);
5828 if (status)
5829 eir_len = 0;
5830 else
5831 eir_len = 9 + 3 + 18 + 18 + 3;
5832 break;
5833 default:
5834 status = MGMT_STATUS_INVALID_PARAMS;
5835 eir_len = 0;
5836 break;
5837 }
5838 } else {
5839 status = MGMT_STATUS_NOT_POWERED;
5840 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005841 }
5842
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005843 rp_len = sizeof(*rp) + eir_len;
5844 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005845 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005846 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005847
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005848 if (status)
5849 goto complete;
5850
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005851 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005852
5853 eir_len = 0;
5854 switch (cp->type) {
5855 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005856 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5857 err = read_local_ssp_oob_req(hdev, sk, cp);
5858 hci_dev_unlock(hdev);
5859 if (!err)
5860 goto done;
5861
5862 status = MGMT_STATUS_FAILED;
5863 goto complete;
5864 } else {
5865 eir_len = eir_append_data(rp->eir, eir_len,
5866 EIR_CLASS_OF_DEV,
5867 hdev->dev_class, 3);
5868 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005869 break;
5870 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005871 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5872 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005873 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005874 status = MGMT_STATUS_FAILED;
5875 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005876 }
5877
Marcel Holtmanne2135682015-04-02 12:00:58 -07005878 /* This should return the active RPA, but since the RPA
5879 * is only programmed on demand, it is really hard to fill
5880 * this in at the moment. For now disallow retrieving
5881 * local out-of-band data when privacy is in use.
5882 *
5883 * Returning the identity address will not help here since
5884 * pairing happens before the identity resolving key is
5885 * known and thus the connection establishment happens
5886 * based on the RPA and not the identity address.
5887 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005888 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005889 hci_dev_unlock(hdev);
5890 status = MGMT_STATUS_REJECTED;
5891 goto complete;
5892 }
5893
5894 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5895 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5896 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5897 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005898 memcpy(addr, &hdev->static_addr, 6);
5899 addr[6] = 0x01;
5900 } else {
5901 memcpy(addr, &hdev->bdaddr, 6);
5902 addr[6] = 0x00;
5903 }
5904
5905 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5906 addr, sizeof(addr));
5907
5908 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5909 role = 0x02;
5910 else
5911 role = 0x01;
5912
5913 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5914 &role, sizeof(role));
5915
Marcel Holtmann5082a592015-03-16 12:39:00 -07005916 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5917 eir_len = eir_append_data(rp->eir, eir_len,
5918 EIR_LE_SC_CONFIRM,
5919 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005920
Marcel Holtmann5082a592015-03-16 12:39:00 -07005921 eir_len = eir_append_data(rp->eir, eir_len,
5922 EIR_LE_SC_RANDOM,
5923 rand, sizeof(rand));
5924 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005925
Johan Hedbergf2252572015-11-18 12:49:20 +02005926 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005927
5928 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5929 flags |= LE_AD_NO_BREDR;
5930
5931 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5932 &flags, sizeof(flags));
5933 break;
5934 }
5935
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005936 hci_dev_unlock(hdev);
5937
Marcel Holtmann72000df2015-03-16 16:11:21 -07005938 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5939
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005940 status = MGMT_STATUS_SUCCESS;
5941
5942complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005943 rp->type = cp->type;
5944 rp->eir_len = cpu_to_le16(eir_len);
5945
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005946 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005947 status, rp, sizeof(*rp) + eir_len);
5948 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005949 goto done;
5950
5951 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5952 rp, sizeof(*rp) + eir_len,
5953 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005954
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005955done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005956 kfree(rp);
5957
5958 return err;
5959}
5960
Arman Uguray089fa8c2015-03-25 18:53:45 -07005961static u32 get_supported_adv_flags(struct hci_dev *hdev)
5962{
5963 u32 flags = 0;
5964
5965 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5966 flags |= MGMT_ADV_FLAG_DISCOV;
5967 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5968 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02005969 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02005970 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005971
5972 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5973 flags |= MGMT_ADV_FLAG_TX_POWER;
5974
5975 return flags;
5976}
5977
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005978static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5979 void *data, u16 data_len)
5980{
5981 struct mgmt_rp_read_adv_features *rp;
5982 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005983 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005984 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005985 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005986 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005987
5988 BT_DBG("%s", hdev->name);
5989
Arman Uguray089fa8c2015-03-25 18:53:45 -07005990 if (!lmp_le_capable(hdev))
5991 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5992 MGMT_STATUS_REJECTED);
5993
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005994 hci_dev_lock(hdev);
5995
Johan Hedberg02c04af2015-11-26 12:15:58 +02005996 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005997 rp = kmalloc(rp_len, GFP_ATOMIC);
5998 if (!rp) {
5999 hci_dev_unlock(hdev);
6000 return -ENOMEM;
6001 }
6002
Arman Uguray089fa8c2015-03-25 18:53:45 -07006003 supported_flags = get_supported_adv_flags(hdev);
6004
6005 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006006 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6007 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006008 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02006009 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006010
Johan Hedberg02c04af2015-11-26 12:15:58 +02006011 instance = rp->instance;
6012 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6013 *instance = adv_instance->instance;
6014 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07006015 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006016
6017 hci_dev_unlock(hdev);
6018
6019 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6020 MGMT_STATUS_SUCCESS, rp, rp_len);
6021
6022 kfree(rp);
6023
6024 return err;
6025}
6026
Szymon Janc2bb368702016-09-18 12:50:05 +02006027static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006028{
Arman Uguray4117ed72015-03-23 15:57:14 -07006029 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006030
Marcel Holtmann31a32482015-11-19 16:16:42 +01006031 if (is_adv_data) {
6032 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6033 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006034 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006035 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006036
Szymon Janc2bb368702016-09-18 12:50:05 +02006037 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006038 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006039 } else {
6040 /* at least 1 byte of name should fit in */
6041 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
6042 max_len -= 3;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006043
Szymon Janc2bb368702016-09-18 12:50:05 +02006044 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006045 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006046 }
6047
Szymon Janc2bb368702016-09-18 12:50:05 +02006048 return max_len;
6049}
6050
6051static bool flags_managed(u32 adv_flags)
6052{
6053 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6054 MGMT_ADV_FLAG_LIMITED_DISCOV |
6055 MGMT_ADV_FLAG_MANAGED_FLAGS);
6056}
6057
6058static bool tx_power_managed(u32 adv_flags)
6059{
6060 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6061}
6062
6063static bool name_managed(u32 adv_flags)
6064{
6065 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6066}
6067
6068static bool appearance_managed(u32 adv_flags)
6069{
6070 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6071}
6072
6073static bool tlv_data_is_valid(u32 adv_flags, u8 *data, u8 len, bool is_adv_data)
6074{
6075 int i, cur_len;
6076 u8 max_len;
6077
6078 max_len = tlv_data_max_len(adv_flags, is_adv_data);
6079
Arman Uguray4117ed72015-03-23 15:57:14 -07006080 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006081 return false;
6082
Arman Uguray4117ed72015-03-23 15:57:14 -07006083 /* Make sure that the data is correctly formatted. */
6084 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6085 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006086
Szymon Janc9c9db782016-09-18 12:50:06 +02006087 if (data[i + 1] == EIR_FLAGS &&
6088 (!is_adv_data || flags_managed(adv_flags)))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006089 return false;
6090
Szymon Janc2bb368702016-09-18 12:50:05 +02006091 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6092 return false;
6093
6094 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6095 return false;
6096
6097 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6098 return false;
6099
6100 if (data[i + 1] == EIR_APPEARANCE &&
6101 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006102 return false;
6103
Arman Uguray24b4f382015-03-23 15:57:12 -07006104 /* If the current field length would exceed the total data
6105 * length, then it's invalid.
6106 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006107 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006108 return false;
6109 }
6110
6111 return true;
6112}
6113
Arman Uguray24b4f382015-03-23 15:57:12 -07006114static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6115 u16 opcode)
6116{
6117 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006118 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006119 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006120 struct adv_info *adv_instance, *n;
6121 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006122
6123 BT_DBG("status %d", status);
6124
6125 hci_dev_lock(hdev);
6126
6127 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6128
Florian Grandelfffd38b2015-06-18 03:16:47 +02006129 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6130 if (!adv_instance->pending)
6131 continue;
6132
6133 if (!status) {
6134 adv_instance->pending = false;
6135 continue;
6136 }
6137
6138 instance = adv_instance->instance;
6139
6140 if (hdev->cur_adv_instance == instance)
6141 cancel_adv_timeout(hdev);
6142
6143 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006144 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006145 }
6146
6147 if (!cmd)
6148 goto unlock;
6149
Florian Grandelfffd38b2015-06-18 03:16:47 +02006150 cp = cmd->param;
6151 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006152
6153 if (status)
6154 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6155 mgmt_status(status));
6156 else
6157 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6158 mgmt_status(status), &rp, sizeof(rp));
6159
6160 mgmt_pending_remove(cmd);
6161
6162unlock:
6163 hci_dev_unlock(hdev);
6164}
6165
6166static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6167 void *data, u16 data_len)
6168{
6169 struct mgmt_cp_add_advertising *cp = data;
6170 struct mgmt_rp_add_advertising rp;
6171 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006172 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006173 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006174 u16 timeout, duration;
6175 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6176 u8 schedule_instance = 0;
6177 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006178 int err;
6179 struct mgmt_pending_cmd *cmd;
6180 struct hci_request req;
6181
6182 BT_DBG("%s", hdev->name);
6183
6184 status = mgmt_le_support(hdev);
6185 if (status)
6186 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6187 status);
6188
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006189 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6190 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6191 MGMT_STATUS_INVALID_PARAMS);
6192
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006193 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6194 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6195 MGMT_STATUS_INVALID_PARAMS);
6196
Arman Uguray24b4f382015-03-23 15:57:12 -07006197 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006198 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006199 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006200
Florian Grandelfffd38b2015-06-18 03:16:47 +02006201 /* The current implementation only supports a subset of the specified
6202 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006203 */
6204 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006205 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006206 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6207 MGMT_STATUS_INVALID_PARAMS);
6208
6209 hci_dev_lock(hdev);
6210
Arman Uguray912098a2015-03-23 15:57:15 -07006211 if (timeout && !hdev_is_powered(hdev)) {
6212 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6213 MGMT_STATUS_REJECTED);
6214 goto unlock;
6215 }
6216
Arman Uguray24b4f382015-03-23 15:57:12 -07006217 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006218 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006219 pending_find(MGMT_OP_SET_LE, hdev)) {
6220 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6221 MGMT_STATUS_BUSY);
6222 goto unlock;
6223 }
6224
Szymon Janc5e2c59e2016-09-18 12:50:04 +02006225 if (!tlv_data_is_valid(flags, cp->data, cp->adv_data_len, true) ||
6226 !tlv_data_is_valid(flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006227 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006228 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6229 MGMT_STATUS_INVALID_PARAMS);
6230 goto unlock;
6231 }
6232
Florian Grandelfffd38b2015-06-18 03:16:47 +02006233 err = hci_add_adv_instance(hdev, cp->instance, flags,
6234 cp->adv_data_len, cp->data,
6235 cp->scan_rsp_len,
6236 cp->data + cp->adv_data_len,
6237 timeout, duration);
6238 if (err < 0) {
6239 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6240 MGMT_STATUS_FAILED);
6241 goto unlock;
6242 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006243
Florian Grandelfffd38b2015-06-18 03:16:47 +02006244 /* Only trigger an advertising added event if a new instance was
6245 * actually added.
6246 */
6247 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006248 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006249
Florian Grandelfffd38b2015-06-18 03:16:47 +02006250 if (hdev->cur_adv_instance == cp->instance) {
6251 /* If the currently advertised instance is being changed then
6252 * cancel the current advertising and schedule the next
6253 * instance. If there is only one instance then the overridden
6254 * advertising data will be visible right away.
6255 */
6256 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006257
Florian Grandelfffd38b2015-06-18 03:16:47 +02006258 next_instance = hci_get_next_instance(hdev, cp->instance);
6259 if (next_instance)
6260 schedule_instance = next_instance->instance;
6261 } else if (!hdev->adv_instance_timeout) {
6262 /* Immediately advertise the new instance if no other
6263 * instance is currently being advertised.
6264 */
6265 schedule_instance = cp->instance;
6266 }
Arman Uguray912098a2015-03-23 15:57:15 -07006267
Florian Grandelfffd38b2015-06-18 03:16:47 +02006268 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6269 * there is no instance to be advertised then we have no HCI
6270 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006271 */
6272 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006273 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6274 !schedule_instance) {
6275 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006276 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6277 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6278 goto unlock;
6279 }
6280
6281 /* We're good to go, update advertising data, parameters, and start
6282 * advertising.
6283 */
6284 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6285 data_len);
6286 if (!cmd) {
6287 err = -ENOMEM;
6288 goto unlock;
6289 }
6290
6291 hci_req_init(&req, hdev);
6292
Johan Hedbergf2252572015-11-18 12:49:20 +02006293 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006294
Florian Grandelfffd38b2015-06-18 03:16:47 +02006295 if (!err)
6296 err = hci_req_run(&req, add_advertising_complete);
6297
Arman Uguray24b4f382015-03-23 15:57:12 -07006298 if (err < 0)
6299 mgmt_pending_remove(cmd);
6300
6301unlock:
6302 hci_dev_unlock(hdev);
6303
6304 return err;
6305}
6306
Arman Ugurayda9293352015-03-23 15:57:13 -07006307static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6308 u16 opcode)
6309{
6310 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006311 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006312 struct mgmt_rp_remove_advertising rp;
6313
6314 BT_DBG("status %d", status);
6315
6316 hci_dev_lock(hdev);
6317
6318 /* A failure status here only means that we failed to disable
6319 * advertising. Otherwise, the advertising instance has been removed,
6320 * so report success.
6321 */
6322 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6323 if (!cmd)
6324 goto unlock;
6325
Florian Grandel01948332015-06-18 03:16:48 +02006326 cp = cmd->param;
6327 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006328
6329 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6330 &rp, sizeof(rp));
6331 mgmt_pending_remove(cmd);
6332
6333unlock:
6334 hci_dev_unlock(hdev);
6335}
6336
6337static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6338 void *data, u16 data_len)
6339{
6340 struct mgmt_cp_remove_advertising *cp = data;
6341 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006342 struct mgmt_pending_cmd *cmd;
6343 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006344 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006345
6346 BT_DBG("%s", hdev->name);
6347
Arman Ugurayda9293352015-03-23 15:57:13 -07006348 hci_dev_lock(hdev);
6349
Johan Hedberg952497b2015-06-18 21:05:31 +03006350 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006351 err = mgmt_cmd_status(sk, hdev->id,
6352 MGMT_OP_REMOVE_ADVERTISING,
6353 MGMT_STATUS_INVALID_PARAMS);
6354 goto unlock;
6355 }
6356
Arman Ugurayda9293352015-03-23 15:57:13 -07006357 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6358 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6359 pending_find(MGMT_OP_SET_LE, hdev)) {
6360 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6361 MGMT_STATUS_BUSY);
6362 goto unlock;
6363 }
6364
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006365 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006366 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6367 MGMT_STATUS_INVALID_PARAMS);
6368 goto unlock;
6369 }
6370
Florian Grandel01948332015-06-18 03:16:48 +02006371 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006372
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006373 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006374
Florian Grandel01948332015-06-18 03:16:48 +02006375 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006376 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006377
Florian Grandel01948332015-06-18 03:16:48 +02006378 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6379 * flag is set or the device isn't powered then we have no HCI
6380 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006381 */
Florian Grandel01948332015-06-18 03:16:48 +02006382 if (skb_queue_empty(&req.cmd_q) ||
6383 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006384 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006385 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006386 err = mgmt_cmd_complete(sk, hdev->id,
6387 MGMT_OP_REMOVE_ADVERTISING,
6388 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6389 goto unlock;
6390 }
6391
6392 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6393 data_len);
6394 if (!cmd) {
6395 err = -ENOMEM;
6396 goto unlock;
6397 }
6398
Arman Ugurayda9293352015-03-23 15:57:13 -07006399 err = hci_req_run(&req, remove_advertising_complete);
6400 if (err < 0)
6401 mgmt_pending_remove(cmd);
6402
6403unlock:
6404 hci_dev_unlock(hdev);
6405
6406 return err;
6407}
6408
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006409static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6410 void *data, u16 data_len)
6411{
6412 struct mgmt_cp_get_adv_size_info *cp = data;
6413 struct mgmt_rp_get_adv_size_info rp;
6414 u32 flags, supported_flags;
6415 int err;
6416
6417 BT_DBG("%s", hdev->name);
6418
6419 if (!lmp_le_capable(hdev))
6420 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6421 MGMT_STATUS_REJECTED);
6422
6423 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6424 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6425 MGMT_STATUS_INVALID_PARAMS);
6426
6427 flags = __le32_to_cpu(cp->flags);
6428
6429 /* The current implementation only supports a subset of the specified
6430 * flags.
6431 */
6432 supported_flags = get_supported_adv_flags(hdev);
6433 if (flags & ~supported_flags)
6434 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6435 MGMT_STATUS_INVALID_PARAMS);
6436
6437 rp.instance = cp->instance;
6438 rp.flags = cp->flags;
6439 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6440 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6441
6442 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6443 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6444
6445 return err;
6446}
6447
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006448static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006449 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006450 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006451 HCI_MGMT_NO_HDEV |
6452 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006453 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006454 HCI_MGMT_NO_HDEV |
6455 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006456 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006457 HCI_MGMT_NO_HDEV |
6458 HCI_MGMT_UNTRUSTED },
6459 { read_controller_info, MGMT_READ_INFO_SIZE,
6460 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006461 { set_powered, MGMT_SETTING_SIZE },
6462 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6463 { set_connectable, MGMT_SETTING_SIZE },
6464 { set_fast_connectable, MGMT_SETTING_SIZE },
6465 { set_bondable, MGMT_SETTING_SIZE },
6466 { set_link_security, MGMT_SETTING_SIZE },
6467 { set_ssp, MGMT_SETTING_SIZE },
6468 { set_hs, MGMT_SETTING_SIZE },
6469 { set_le, MGMT_SETTING_SIZE },
6470 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6471 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6472 { add_uuid, MGMT_ADD_UUID_SIZE },
6473 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006474 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6475 HCI_MGMT_VAR_LEN },
6476 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6477 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006478 { disconnect, MGMT_DISCONNECT_SIZE },
6479 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6480 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6481 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6482 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6483 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6484 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6485 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6486 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6487 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6488 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6489 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006490 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6491 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6492 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006493 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6494 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6495 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6496 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6497 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6498 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6499 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6500 { set_advertising, MGMT_SETTING_SIZE },
6501 { set_bredr, MGMT_SETTING_SIZE },
6502 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6503 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6504 { set_secure_conn, MGMT_SETTING_SIZE },
6505 { set_debug_keys, MGMT_SETTING_SIZE },
6506 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006507 { load_irks, MGMT_LOAD_IRKS_SIZE,
6508 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006509 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6510 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6511 { add_device, MGMT_ADD_DEVICE_SIZE },
6512 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006513 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6514 HCI_MGMT_VAR_LEN },
6515 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006516 HCI_MGMT_NO_HDEV |
6517 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006518 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006519 HCI_MGMT_UNCONFIGURED |
6520 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006521 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6522 HCI_MGMT_UNCONFIGURED },
6523 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6524 HCI_MGMT_UNCONFIGURED },
6525 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6526 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006527 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006528 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006529 HCI_MGMT_NO_HDEV |
6530 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006531 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006532 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6533 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006534 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006535 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006536 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006537 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6538 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006539 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006540};
6541
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006542void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006543{
Marcel Holtmannced85542015-03-14 19:27:56 -07006544 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006545
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006546 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6547 return;
6548
Marcel Holtmannf9207332015-03-14 19:27:55 -07006549 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006550 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006551 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6552 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6553 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006554 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006555 } else {
6556 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6557 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006558 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006559 }
6560 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006561 case HCI_AMP:
6562 ev.type = 0x02;
6563 break;
6564 default:
6565 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006566 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006567
6568 ev.bus = hdev->bus;
6569
6570 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6571 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006572}
6573
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006574void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006575{
Marcel Holtmannced85542015-03-14 19:27:56 -07006576 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006577 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006578
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006579 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6580 return;
6581
Marcel Holtmannf9207332015-03-14 19:27:55 -07006582 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006583 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006584 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006585
Marcel Holtmannf9207332015-03-14 19:27:55 -07006586 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6587 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6588 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006589 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006590 } else {
6591 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6592 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006593 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006594 }
6595 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006596 case HCI_AMP:
6597 ev.type = 0x02;
6598 break;
6599 default:
6600 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006601 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006602
6603 ev.bus = hdev->bus;
6604
6605 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6606 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006607}
6608
Andre Guedes6046dc32014-02-26 20:21:51 -03006609/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006610static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006611{
6612 struct hci_conn_params *p;
6613
6614 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006615 /* Needed for AUTO_OFF case where might not "really"
6616 * have been powered off.
6617 */
6618 list_del_init(&p->action);
6619
6620 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006621 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006622 case HCI_AUTO_CONN_ALWAYS:
6623 list_add(&p->action, &hdev->pend_le_conns);
6624 break;
6625 case HCI_AUTO_CONN_REPORT:
6626 list_add(&p->action, &hdev->pend_le_reports);
6627 break;
6628 default:
6629 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006630 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006631 }
6632}
6633
Johan Hedberg2ff13892015-11-25 16:15:44 +02006634void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006635{
6636 struct cmd_lookup match = { NULL, hdev };
6637
Johan Hedberg2ff13892015-11-25 16:15:44 +02006638 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006639
Johan Hedberg2ff13892015-11-25 16:15:44 +02006640 hci_dev_lock(hdev);
6641
6642 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006643 restart_le_actions(hdev);
6644 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006645 }
6646
Johan Hedberg229ab392013-03-15 17:06:53 -05006647 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6648
6649 new_settings(hdev, match.sk);
6650
Johan Hedberg229ab392013-03-15 17:06:53 -05006651 if (match.sk)
6652 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006653
6654 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006655}
6656
Johan Hedberg2ff13892015-11-25 16:15:44 +02006657void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006658{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006659 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006660 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006661
Johan Hedberg229ab392013-03-15 17:06:53 -05006662 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006663
6664 /* If the power off is because of hdev unregistration let
6665 * use the appropriate INVALID_INDEX status. Otherwise use
6666 * NOT_POWERED. We cover both scenarios here since later in
6667 * mgmt_index_removed() any hci_conn callbacks will have already
6668 * been triggered, potentially causing misleading DISCONNECTED
6669 * status responses.
6670 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006671 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006672 status = MGMT_STATUS_INVALID_INDEX;
6673 else
6674 status = MGMT_STATUS_NOT_POWERED;
6675
6676 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006677
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006678 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02006679 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6680 zero_cod, sizeof(zero_cod),
6681 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006682 ext_info_changed(hdev, NULL);
6683 }
Johan Hedberg229ab392013-03-15 17:06:53 -05006684
Johan Hedberg2ff13892015-11-25 16:15:44 +02006685 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006686
6687 if (match.sk)
6688 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006689}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006690
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006691void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006692{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006693 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006694 u8 status;
6695
Johan Hedberg333ae952015-03-17 13:48:47 +02006696 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006697 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006698 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006699
6700 if (err == -ERFKILL)
6701 status = MGMT_STATUS_RFKILLED;
6702 else
6703 status = MGMT_STATUS_FAILED;
6704
Johan Hedberga69e8372015-03-06 21:08:53 +02006705 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006706
6707 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006708}
6709
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006710void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6711 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006712{
Johan Hedberg86742e12011-11-07 23:13:38 +02006713 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006714
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006715 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006716
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006717 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006718 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006719 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006720 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006721 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006722 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006723
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006724 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006725}
Johan Hedbergf7520542011-01-20 12:34:39 +02006726
Johan Hedbergd7b25452014-05-23 13:19:53 +03006727static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6728{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006729 switch (ltk->type) {
6730 case SMP_LTK:
6731 case SMP_LTK_SLAVE:
6732 if (ltk->authenticated)
6733 return MGMT_LTK_AUTHENTICATED;
6734 return MGMT_LTK_UNAUTHENTICATED;
6735 case SMP_LTK_P256:
6736 if (ltk->authenticated)
6737 return MGMT_LTK_P256_AUTH;
6738 return MGMT_LTK_P256_UNAUTH;
6739 case SMP_LTK_P256_DEBUG:
6740 return MGMT_LTK_P256_DEBUG;
6741 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006742
6743 return MGMT_LTK_UNAUTHENTICATED;
6744}
6745
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006746void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006747{
6748 struct mgmt_ev_new_long_term_key ev;
6749
6750 memset(&ev, 0, sizeof(ev));
6751
Marcel Holtmann5192d302014-02-19 17:11:58 -08006752 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006753 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006754 * to store long term keys. Their addresses will change the
6755 * next time around.
6756 *
6757 * Only when a remote device provides an identity address
6758 * make sure the long term key is stored. If the remote
6759 * identity is known, the long term keys are internally
6760 * mapped to the identity address. So allow static random
6761 * and public addresses here.
6762 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006763 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6764 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6765 ev.store_hint = 0x00;
6766 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006767 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006768
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006769 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006770 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006771 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006772 ev.key.enc_size = key->enc_size;
6773 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006774 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006775
Johan Hedberg2ceba532014-06-16 19:25:16 +03006776 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006777 ev.key.master = 1;
6778
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006779 /* Make sure we copy only the significant bytes based on the
6780 * encryption key size, and set the rest of the value to zeroes.
6781 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006782 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006783 memset(ev.key.val + key->enc_size, 0,
6784 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006785
Marcel Holtmann083368f2013-10-15 14:26:29 -07006786 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006787}
6788
Johan Hedbergcad20c22015-10-12 13:36:19 +02006789void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006790{
6791 struct mgmt_ev_new_irk ev;
6792
6793 memset(&ev, 0, sizeof(ev));
6794
Johan Hedbergcad20c22015-10-12 13:36:19 +02006795 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006796
Johan Hedberg95fbac82014-02-19 15:18:31 +02006797 bacpy(&ev.rpa, &irk->rpa);
6798 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6799 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6800 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6801
6802 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6803}
6804
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006805void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6806 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006807{
6808 struct mgmt_ev_new_csrk ev;
6809
6810 memset(&ev, 0, sizeof(ev));
6811
6812 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006813 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006814 * to store signature resolving keys. Their addresses will change
6815 * the next time around.
6816 *
6817 * Only when a remote device provides an identity address
6818 * make sure the signature resolving key is stored. So allow
6819 * static random and public addresses here.
6820 */
6821 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6822 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6823 ev.store_hint = 0x00;
6824 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006825 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006826
6827 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6828 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006829 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006830 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6831
6832 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6833}
6834
Andre Guedesffb5a8272014-07-01 18:10:11 -03006835void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006836 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6837 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006838{
6839 struct mgmt_ev_new_conn_param ev;
6840
Johan Hedbergc103aea2014-07-02 17:37:34 +03006841 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6842 return;
6843
Andre Guedesffb5a8272014-07-01 18:10:11 -03006844 memset(&ev, 0, sizeof(ev));
6845 bacpy(&ev.addr.bdaddr, bdaddr);
6846 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006847 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006848 ev.min_interval = cpu_to_le16(min_interval);
6849 ev.max_interval = cpu_to_le16(max_interval);
6850 ev.latency = cpu_to_le16(latency);
6851 ev.timeout = cpu_to_le16(timeout);
6852
6853 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6854}
6855
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006856void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6857 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006858{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006859 char buf[512];
6860 struct mgmt_ev_device_connected *ev = (void *) buf;
6861 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006862
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006863 bacpy(&ev->addr.bdaddr, &conn->dst);
6864 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006865
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006866 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006867
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006868 /* We must ensure that the EIR Data fields are ordered and
6869 * unique. Keep it simple for now and avoid the problem by not
6870 * adding any BR/EDR data to the LE adv.
6871 */
6872 if (conn->le_adv_data_len > 0) {
6873 memcpy(&ev->eir[eir_len],
6874 conn->le_adv_data, conn->le_adv_data_len);
6875 eir_len = conn->le_adv_data_len;
6876 } else {
6877 if (name_len > 0)
6878 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6879 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006880
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006881 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006882 eir_len = eir_append_data(ev->eir, eir_len,
6883 EIR_CLASS_OF_DEV,
6884 conn->dev_class, 3);
6885 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006886
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006887 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006888
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006889 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6890 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006891}
6892
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006893static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006894{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006895 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006896
Johan Hedbergf5818c22014-12-05 13:36:02 +02006897 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006898
6899 *sk = cmd->sk;
6900 sock_hold(*sk);
6901
Johan Hedberga664b5b2011-02-19 12:06:02 -03006902 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006903}
6904
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006905static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006906{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006907 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006908 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006909
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006910 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6911
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006912 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006913 mgmt_pending_remove(cmd);
6914}
6915
Johan Hedberg84c61d92014-08-01 11:13:30 +03006916bool mgmt_powering_down(struct hci_dev *hdev)
6917{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006918 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006919 struct mgmt_mode *cp;
6920
Johan Hedberg333ae952015-03-17 13:48:47 +02006921 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006922 if (!cmd)
6923 return false;
6924
6925 cp = cmd->param;
6926 if (!cp->val)
6927 return true;
6928
6929 return false;
6930}
6931
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006932void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006933 u8 link_type, u8 addr_type, u8 reason,
6934 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006935{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006936 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006937 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006938
Johan Hedberg84c61d92014-08-01 11:13:30 +03006939 /* The connection is still in hci_conn_hash so test for 1
6940 * instead of 0 to know if this is the last one.
6941 */
6942 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6943 cancel_delayed_work(&hdev->power_off);
6944 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006945 }
6946
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006947 if (!mgmt_connected)
6948 return;
6949
Andre Guedes57eb7762013-10-30 19:01:41 -03006950 if (link_type != ACL_LINK && link_type != LE_LINK)
6951 return;
6952
Johan Hedberg744cf192011-11-08 20:40:14 +02006953 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006954
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006955 bacpy(&ev.addr.bdaddr, bdaddr);
6956 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6957 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006958
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006959 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006960
6961 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006962 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006963
Johan Hedberg124f6e32012-02-09 13:50:12 +02006964 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006965 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006966}
6967
Marcel Holtmann78929242013-10-06 23:55:47 -07006968void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6969 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006970{
Andre Guedes3655bba2013-10-30 19:01:40 -03006971 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6972 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006973 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006974
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006975 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6976 hdev);
6977
Johan Hedberg333ae952015-03-17 13:48:47 +02006978 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006979 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006980 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006981
Andre Guedes3655bba2013-10-30 19:01:40 -03006982 cp = cmd->param;
6983
6984 if (bacmp(bdaddr, &cp->addr.bdaddr))
6985 return;
6986
6987 if (cp->addr.type != bdaddr_type)
6988 return;
6989
Johan Hedbergf5818c22014-12-05 13:36:02 +02006990 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006991 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006992}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006993
Marcel Holtmann445608d2013-10-06 23:55:48 -07006994void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6995 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006996{
6997 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006998
Johan Hedberg84c61d92014-08-01 11:13:30 +03006999 /* The connection is still in hci_conn_hash so test for 1
7000 * instead of 0 to know if this is the last one.
7001 */
7002 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7003 cancel_delayed_work(&hdev->power_off);
7004 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007005 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007006
Johan Hedberg4c659c32011-11-07 23:13:39 +02007007 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007008 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007009 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007010
Marcel Holtmann445608d2013-10-06 23:55:48 -07007011 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007012}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007013
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007014void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007015{
7016 struct mgmt_ev_pin_code_request ev;
7017
Johan Hedbergd8457692012-02-17 14:24:57 +02007018 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007019 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007020 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007021
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007022 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007023}
7024
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007025void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7026 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007027{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007028 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007029
Johan Hedberg333ae952015-03-17 13:48:47 +02007030 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007031 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007032 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007033
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007034 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007035 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007036}
7037
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007038void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7039 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007040{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007041 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007042
Johan Hedberg333ae952015-03-17 13:48:47 +02007043 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007044 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007045 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007046
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007047 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007048 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007049}
Johan Hedberga5c29682011-02-19 12:05:57 -03007050
Johan Hedberg744cf192011-11-08 20:40:14 +02007051int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007052 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007053 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007054{
7055 struct mgmt_ev_user_confirm_request ev;
7056
Johan Hedberg744cf192011-11-08 20:40:14 +02007057 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007058
Johan Hedberg272d90d2012-02-09 15:26:12 +02007059 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007060 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007061 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007062 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007063
Johan Hedberg744cf192011-11-08 20:40:14 +02007064 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007065 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007066}
7067
Johan Hedberg272d90d2012-02-09 15:26:12 +02007068int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007069 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007070{
7071 struct mgmt_ev_user_passkey_request ev;
7072
7073 BT_DBG("%s", hdev->name);
7074
Johan Hedberg272d90d2012-02-09 15:26:12 +02007075 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007076 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007077
7078 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007079 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007080}
7081
Brian Gix0df4c182011-11-16 13:53:13 -08007082static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007083 u8 link_type, u8 addr_type, u8 status,
7084 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007085{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007086 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007087
Johan Hedberg333ae952015-03-17 13:48:47 +02007088 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007089 if (!cmd)
7090 return -ENOENT;
7091
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007092 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007093 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007094
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007095 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007096}
7097
Johan Hedberg744cf192011-11-08 20:40:14 +02007098int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007099 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007100{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007101 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007102 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007103}
7104
Johan Hedberg272d90d2012-02-09 15:26:12 +02007105int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007106 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007107{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007108 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007109 status,
7110 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007111}
Johan Hedberg2a611692011-02-19 12:06:00 -03007112
Brian Gix604086b2011-11-23 08:28:33 -08007113int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007114 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007115{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007116 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007117 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007118}
7119
Johan Hedberg272d90d2012-02-09 15:26:12 +02007120int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007121 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007122{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007123 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007124 status,
7125 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007126}
7127
Johan Hedberg92a25252012-09-06 18:39:26 +03007128int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7129 u8 link_type, u8 addr_type, u32 passkey,
7130 u8 entered)
7131{
7132 struct mgmt_ev_passkey_notify ev;
7133
7134 BT_DBG("%s", hdev->name);
7135
7136 bacpy(&ev.addr.bdaddr, bdaddr);
7137 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7138 ev.passkey = __cpu_to_le32(passkey);
7139 ev.entered = entered;
7140
7141 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7142}
7143
Johan Hedberge1e930f2014-09-08 17:09:49 -07007144void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007145{
7146 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007147 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007148 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007149
Johan Hedberge1e930f2014-09-08 17:09:49 -07007150 bacpy(&ev.addr.bdaddr, &conn->dst);
7151 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7152 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007153
Johan Hedberge1e930f2014-09-08 17:09:49 -07007154 cmd = find_pairing(conn);
7155
7156 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7157 cmd ? cmd->sk : NULL);
7158
Johan Hedberga511b352014-12-11 21:45:45 +02007159 if (cmd) {
7160 cmd->cmd_complete(cmd, status);
7161 mgmt_pending_remove(cmd);
7162 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007163}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007164
Marcel Holtmann464996a2013-10-15 14:26:24 -07007165void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007166{
7167 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007168 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007169
7170 if (status) {
7171 u8 mgmt_err = mgmt_status(status);
7172 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007173 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007174 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007175 }
7176
Marcel Holtmann464996a2013-10-15 14:26:24 -07007177 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007178 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007179 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007180 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007181
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007182 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007183 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007184
Johan Hedberg47990ea2012-02-22 11:58:37 +02007185 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007186 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007187
7188 if (match.sk)
7189 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007190}
7191
Johan Hedberg890ea892013-03-15 17:06:52 -05007192static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007193{
Johan Hedberg890ea892013-03-15 17:06:52 -05007194 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007195 struct hci_cp_write_eir cp;
7196
Johan Hedberg976eb202012-10-24 21:12:01 +03007197 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007198 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007199
Johan Hedbergc80da272012-02-22 15:38:48 +02007200 memset(hdev->eir, 0, sizeof(hdev->eir));
7201
Johan Hedbergcacaf522012-02-21 00:52:42 +02007202 memset(&cp, 0, sizeof(cp));
7203
Johan Hedberg890ea892013-03-15 17:06:52 -05007204 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007205}
7206
Marcel Holtmann3e248562013-10-15 14:26:25 -07007207void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007208{
7209 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007210 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007211 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007212
7213 if (status) {
7214 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007215
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007216 if (enable && hci_dev_test_and_clear_flag(hdev,
7217 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007218 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007219 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007220 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007221
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007222 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7223 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007224 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007225 }
7226
7227 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007228 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007229 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007230 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007231 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007232 changed = hci_dev_test_and_clear_flag(hdev,
7233 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007234 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007235 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007236 }
7237
7238 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7239
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007240 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007241 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007242
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007243 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007244 sock_put(match.sk);
7245
Johan Hedberg890ea892013-03-15 17:06:52 -05007246 hci_req_init(&req, hdev);
7247
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007248 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7249 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007250 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7251 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007252 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007253 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007254 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007255 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007256
7257 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007258}
7259
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007260static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007261{
7262 struct cmd_lookup *match = data;
7263
Johan Hedberg90e70452012-02-23 23:09:40 +02007264 if (match->sk == NULL) {
7265 match->sk = cmd->sk;
7266 sock_hold(match->sk);
7267 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007268}
7269
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007270void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7271 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007272{
Johan Hedberg90e70452012-02-23 23:09:40 +02007273 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007274
Johan Hedberg92da6092013-03-15 17:06:55 -05007275 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7276 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7277 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007278
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007279 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007280 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7281 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007282 ext_info_changed(hdev, NULL);
7283 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007284
7285 if (match.sk)
7286 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007287}
7288
Marcel Holtmann7667da32013-10-15 14:26:27 -07007289void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007290{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007291 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007292 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007293
Johan Hedberg13928972013-03-15 17:07:00 -05007294 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007295 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007296
7297 memset(&ev, 0, sizeof(ev));
7298 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007299 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007300
Johan Hedberg333ae952015-03-17 13:48:47 +02007301 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007302 if (!cmd) {
7303 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007304
Johan Hedberg13928972013-03-15 17:07:00 -05007305 /* If this is a HCI command related to powering on the
7306 * HCI dev don't send any mgmt signals.
7307 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007308 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007309 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007310 }
7311
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007312 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7313 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007314 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007315}
Szymon Jancc35938b2011-03-22 13:12:21 +01007316
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007317static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7318{
7319 int i;
7320
7321 for (i = 0; i < uuid_count; i++) {
7322 if (!memcmp(uuid, uuids[i], 16))
7323 return true;
7324 }
7325
7326 return false;
7327}
7328
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007329static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7330{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007331 u16 parsed = 0;
7332
7333 while (parsed < eir_len) {
7334 u8 field_len = eir[0];
7335 u8 uuid[16];
7336 int i;
7337
7338 if (field_len == 0)
7339 break;
7340
7341 if (eir_len - parsed < field_len + 1)
7342 break;
7343
7344 switch (eir[1]) {
7345 case EIR_UUID16_ALL:
7346 case EIR_UUID16_SOME:
7347 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007348 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007349 uuid[13] = eir[i + 3];
7350 uuid[12] = eir[i + 2];
7351 if (has_uuid(uuid, uuid_count, uuids))
7352 return true;
7353 }
7354 break;
7355 case EIR_UUID32_ALL:
7356 case EIR_UUID32_SOME:
7357 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007358 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007359 uuid[15] = eir[i + 5];
7360 uuid[14] = eir[i + 4];
7361 uuid[13] = eir[i + 3];
7362 uuid[12] = eir[i + 2];
7363 if (has_uuid(uuid, uuid_count, uuids))
7364 return true;
7365 }
7366 break;
7367 case EIR_UUID128_ALL:
7368 case EIR_UUID128_SOME:
7369 for (i = 0; i + 17 <= field_len; i += 16) {
7370 memcpy(uuid, eir + i + 2, 16);
7371 if (has_uuid(uuid, uuid_count, uuids))
7372 return true;
7373 }
7374 break;
7375 }
7376
7377 parsed += field_len + 1;
7378 eir += field_len + 1;
7379 }
7380
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007381 return false;
7382}
7383
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007384static void restart_le_scan(struct hci_dev *hdev)
7385{
7386 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007387 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007388 return;
7389
7390 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7391 hdev->discovery.scan_start +
7392 hdev->discovery.scan_duration))
7393 return;
7394
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007395 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007396 DISCOV_LE_RESTART_DELAY);
7397}
7398
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007399static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7400 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7401{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007402 /* If a RSSI threshold has been specified, and
7403 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7404 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7405 * is set, let it through for further processing, as we might need to
7406 * restart the scan.
7407 *
7408 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7409 * the results are also dropped.
7410 */
7411 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7412 (rssi == HCI_RSSI_INVALID ||
7413 (rssi < hdev->discovery.rssi &&
7414 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7415 return false;
7416
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007417 if (hdev->discovery.uuid_count != 0) {
7418 /* If a list of UUIDs is provided in filter, results with no
7419 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007420 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007421 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7422 hdev->discovery.uuids) &&
7423 !eir_has_uuids(scan_rsp, scan_rsp_len,
7424 hdev->discovery.uuid_count,
7425 hdev->discovery.uuids))
7426 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007427 }
7428
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007429 /* If duplicate filtering does not report RSSI changes, then restart
7430 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007431 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007432 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7433 restart_le_scan(hdev);
7434
7435 /* Validate RSSI value against the RSSI threshold once more. */
7436 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7437 rssi < hdev->discovery.rssi)
7438 return false;
7439 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007440
7441 return true;
7442}
7443
Marcel Holtmann901801b2013-10-06 23:55:51 -07007444void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007445 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7446 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007447{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007448 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007449 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007450 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007451
Johan Hedberg75ce2082014-07-02 22:42:01 +03007452 /* Don't send events for a non-kernel initiated discovery. With
7453 * LE one exception is if we have pend_le_reports > 0 in which
7454 * case we're doing passive scanning and want these events.
7455 */
7456 if (!hci_discovery_active(hdev)) {
7457 if (link_type == ACL_LINK)
7458 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007459 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007460 return;
7461 }
Andre Guedes12602d02013-04-30 15:29:40 -03007462
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007463 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007464 /* We are using service discovery */
7465 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7466 scan_rsp_len))
7467 return;
7468 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007469
Johan Hedberg78b781c2016-01-05 13:19:32 +02007470 if (hdev->discovery.limited) {
7471 /* Check for limited discoverable bit */
7472 if (dev_class) {
7473 if (!(dev_class[1] & 0x20))
7474 return;
7475 } else {
7476 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7477 if (!flags || !(flags[0] & LE_AD_LIMITED))
7478 return;
7479 }
7480 }
7481
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007482 /* Make sure that the buffer is big enough. The 5 extra bytes
7483 * are for the potential CoD field.
7484 */
7485 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007486 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007487
Johan Hedberg1dc06092012-01-15 21:01:23 +02007488 memset(buf, 0, sizeof(buf));
7489
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007490 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7491 * RSSI value was reported as 0 when not available. This behavior
7492 * is kept when using device discovery. This is required for full
7493 * backwards compatibility with the API.
7494 *
7495 * However when using service discovery, the value 127 will be
7496 * returned when the RSSI is not available.
7497 */
Szymon Janc91200e92015-01-22 16:57:05 +01007498 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7499 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007500 rssi = 0;
7501
Johan Hedberg841c5642014-07-07 12:45:54 +03007502 bacpy(&ev->addr.bdaddr, bdaddr);
7503 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007504 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007505 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007506
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007507 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007508 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007509 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007510
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007511 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7512 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007513 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007514 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007515
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007516 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007517 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007518 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007519
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007520 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7521 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007522
Marcel Holtmann901801b2013-10-06 23:55:51 -07007523 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007524}
Johan Hedberga88a9652011-03-30 13:18:12 +03007525
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007526void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7527 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007528{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007529 struct mgmt_ev_device_found *ev;
7530 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7531 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007532
Johan Hedbergb644ba32012-01-17 21:48:47 +02007533 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007534
Johan Hedbergb644ba32012-01-17 21:48:47 +02007535 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007536
Johan Hedbergb644ba32012-01-17 21:48:47 +02007537 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007538 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007539 ev->rssi = rssi;
7540
7541 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007542 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007543
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007544 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007545
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007546 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007547}
Johan Hedberg314b2382011-04-27 10:29:57 -04007548
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007549void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007550{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007551 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007552
Andre Guedes343fb142011-11-22 17:14:19 -03007553 BT_DBG("%s discovering %u", hdev->name, discovering);
7554
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007555 memset(&ev, 0, sizeof(ev));
7556 ev.type = hdev->discovery.type;
7557 ev.discovering = discovering;
7558
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007559 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007560}
Antti Julku5e762442011-08-25 16:48:02 +03007561
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007562static struct hci_mgmt_chan chan = {
7563 .channel = HCI_CHANNEL_CONTROL,
7564 .handler_count = ARRAY_SIZE(mgmt_handlers),
7565 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007566 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007567};
7568
7569int mgmt_init(void)
7570{
7571 return hci_mgmt_chan_register(&chan);
7572}
7573
7574void mgmt_exit(void)
7575{
7576 hci_mgmt_chan_unregister(&chan);
7577}