blob: c96b0adc4971ac2d5da71ea1e1b054cfcc8ffd3a [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
Johan Hedberg87510972016-07-13 10:57:18 +030041#define MGMT_REVISION 13
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
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200881static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
882 void *data, u16 data_len)
883{
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200884 struct mgmt_rp_read_ext_info *rp;
885 char buff[512];
886 u16 eir_len = 0;
887 u8 name_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200888
889 BT_DBG("sock %p %s", sk, hdev->name);
890
891 hci_dev_lock(hdev);
892
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200893 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
894 eir_len = eir_append_data(buff, eir_len,
895 EIR_CLASS_OF_DEV,
896 hdev->dev_class, 3);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200897
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200898 name_len = strlen(hdev->dev_name);
899 eir_len = eir_append_data(buff, eir_len, EIR_NAME_COMPLETE,
900 hdev->dev_name, name_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200901
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200902 name_len = strlen(hdev->short_name);
903 eir_len = eir_append_data(buff, eir_len, EIR_NAME_SHORT,
904 hdev->short_name, name_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200905
Wei Yongjun3e36ca42016-09-10 12:21:22 +0000906 rp = kzalloc(sizeof(*rp) + eir_len, GFP_KERNEL);
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200907 if (!rp)
908 return -ENOMEM;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200909
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200910 rp->eir_len = cpu_to_le16(eir_len);
911 memcpy(rp->eir, buff, eir_len);
912
913 bacpy(&rp->bdaddr, &hdev->bdaddr);
914
915 rp->version = hdev->hci_ver;
916 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
917
918 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
919 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200920
921 hci_dev_unlock(hdev);
922
923 /* If this command is called at least once, then the events
924 * for class of device and local name changes are disabled
925 * and only the new extended controller information event
926 * is used.
927 */
928 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
929 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
930 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
931
MichaƂ Narajowski8a0c9f42016-09-01 16:46:24 +0200932 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
933 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200934}
935
936static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
937{
938 struct mgmt_ev_ext_info_changed ev;
939
940 ev.eir_len = cpu_to_le16(0);
941
942 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, &ev,
943 sizeof(ev), HCI_MGMT_EXT_INFO_EVENTS, skip);
944}
945
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200946static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200947{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200948 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200949
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200950 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
951 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200952}
953
Marcel Holtmann1904a852015-01-11 13:50:44 -0800954static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200955{
956 BT_DBG("%s status 0x%02x", hdev->name, status);
957
Johan Hedberga3172b72014-02-28 09:33:44 +0200958 if (hci_conn_count(hdev) == 0) {
959 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200960 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200961 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200962}
963
Johan Hedbergf2252572015-11-18 12:49:20 +0200964void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700965{
966 struct mgmt_ev_advertising_added ev;
967
968 ev.instance = instance;
969
970 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
971}
972
Johan Hedbergf2252572015-11-18 12:49:20 +0200973void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
974 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700975{
976 struct mgmt_ev_advertising_removed ev;
977
978 ev.instance = instance;
979
980 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
981}
982
Florian Grandel7816b822015-06-18 03:16:45 +0200983static void cancel_adv_timeout(struct hci_dev *hdev)
984{
985 if (hdev->adv_instance_timeout) {
986 hdev->adv_instance_timeout = 0;
987 cancel_delayed_work(&hdev->adv_instance_expire);
988 }
989}
990
Johan Hedberg8b064a32014-02-24 14:52:22 +0200991static int clean_up_hci_state(struct hci_dev *hdev)
992{
993 struct hci_request req;
994 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300995 bool discov_stopped;
996 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200997
998 hci_req_init(&req, hdev);
999
1000 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1001 test_bit(HCI_PSCAN, &hdev->flags)) {
1002 u8 scan = 0x00;
1003 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1004 }
1005
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001006 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001007
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001008 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001009 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001010
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001011 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001012
1013 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001014 /* 0x15 == Terminated due to Power Off */
1015 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001016 }
1017
Johan Hedberg23a48092014-07-08 16:05:06 +03001018 err = hci_req_run(&req, clean_up_hci_complete);
1019 if (!err && discov_stopped)
1020 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1021
1022 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001023}
1024
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001025static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001026 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001028 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001029 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001030 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001032 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001033
Johan Hedberga7e80f22013-01-09 16:05:19 +02001034 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001035 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1036 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001037
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001038 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039
Johan Hedberg333ae952015-03-17 13:48:47 +02001040 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001041 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1042 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001043 goto failed;
1044 }
1045
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001046 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001047 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001048 goto failed;
1049 }
1050
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001051 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1052 if (!cmd) {
1053 err = -ENOMEM;
1054 goto failed;
1055 }
1056
Johan Hedberg8b064a32014-02-24 14:52:22 +02001057 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001058 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001059 err = 0;
1060 } else {
1061 /* Disconnect connections, stop scans, etc */
1062 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001063 if (!err)
1064 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1065 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001066
Johan Hedberg8b064a32014-02-24 14:52:22 +02001067 /* ENODATA means there were no HCI commands queued */
1068 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001069 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001070 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1071 err = 0;
1072 }
1073 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001074
1075failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001076 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001077 return err;
1078}
1079
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001080static int new_settings(struct hci_dev *hdev, struct sock *skip)
1081{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001082 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001083
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001084 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1085 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001086}
1087
Johan Hedberg91a668b2014-07-09 13:28:26 +03001088int mgmt_new_settings(struct hci_dev *hdev)
1089{
1090 return new_settings(hdev, NULL);
1091}
1092
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001093struct cmd_lookup {
1094 struct sock *sk;
1095 struct hci_dev *hdev;
1096 u8 mgmt_status;
1097};
1098
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001099static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001100{
1101 struct cmd_lookup *match = data;
1102
1103 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1104
1105 list_del(&cmd->list);
1106
1107 if (match->sk == NULL) {
1108 match->sk = cmd->sk;
1109 sock_hold(match->sk);
1110 }
1111
1112 mgmt_pending_free(cmd);
1113}
1114
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001115static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001116{
1117 u8 *status = data;
1118
Johan Hedberga69e8372015-03-06 21:08:53 +02001119 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001120 mgmt_pending_remove(cmd);
1121}
1122
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001123static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001124{
1125 if (cmd->cmd_complete) {
1126 u8 *status = data;
1127
1128 cmd->cmd_complete(cmd, *status);
1129 mgmt_pending_remove(cmd);
1130
1131 return;
1132 }
1133
1134 cmd_status_rsp(cmd, data);
1135}
1136
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001137static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001138{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001139 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1140 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001141}
1142
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001143static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001144{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001145 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1146 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001147}
1148
Johan Hedberge6fe7982013-10-02 15:45:22 +03001149static u8 mgmt_bredr_support(struct hci_dev *hdev)
1150{
1151 if (!lmp_bredr_capable(hdev))
1152 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001153 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001154 return MGMT_STATUS_REJECTED;
1155 else
1156 return MGMT_STATUS_SUCCESS;
1157}
1158
1159static u8 mgmt_le_support(struct hci_dev *hdev)
1160{
1161 if (!lmp_le_capable(hdev))
1162 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001163 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001164 return MGMT_STATUS_REJECTED;
1165 else
1166 return MGMT_STATUS_SUCCESS;
1167}
1168
Johan Hedbergaed1a882015-11-22 17:24:44 +03001169void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001170{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001171 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001172
1173 BT_DBG("status 0x%02x", status);
1174
1175 hci_dev_lock(hdev);
1176
Johan Hedberg333ae952015-03-17 13:48:47 +02001177 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001178 if (!cmd)
1179 goto unlock;
1180
1181 if (status) {
1182 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001183 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001184 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001185 goto remove_cmd;
1186 }
1187
Johan Hedbergaed1a882015-11-22 17:24:44 +03001188 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1189 hdev->discov_timeout > 0) {
1190 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1191 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001192 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001193
1194 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001195 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001196
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001197remove_cmd:
1198 mgmt_pending_remove(cmd);
1199
1200unlock:
1201 hci_dev_unlock(hdev);
1202}
1203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001204static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001205 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001206{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001207 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001208 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001209 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001210 int err;
1211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001212 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001213
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001214 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1215 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001216 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1217 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001218
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001219 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001220 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1221 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001222
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001223 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001224
1225 /* Disabling discoverable requires that no timeout is set,
1226 * and enabling limited discoverable requires a timeout.
1227 */
1228 if ((cp->val == 0x00 && timeout > 0) ||
1229 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001230 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1231 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001232
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001233 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001234
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001235 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001236 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1237 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001238 goto failed;
1239 }
1240
Johan Hedberg333ae952015-03-17 13:48:47 +02001241 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1242 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001243 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1244 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001245 goto failed;
1246 }
1247
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001248 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001249 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1250 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001251 goto failed;
1252 }
1253
1254 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001255 bool changed = false;
1256
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001257 /* Setting limited discoverable when powered off is
1258 * not a valid operation since it requires a timeout
1259 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1260 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001261 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001262 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001263 changed = true;
1264 }
1265
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001266 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001267 if (err < 0)
1268 goto failed;
1269
1270 if (changed)
1271 err = new_settings(hdev, sk);
1272
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001273 goto failed;
1274 }
1275
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001276 /* If the current mode is the same, then just update the timeout
1277 * value with the new value. And if only the timeout gets updated,
1278 * then no need for any HCI transactions.
1279 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001280 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1281 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1282 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001283 cancel_delayed_work(&hdev->discov_off);
1284 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001285
Marcel Holtmann36261542013-10-15 08:28:51 -07001286 if (cp->val && hdev->discov_timeout > 0) {
1287 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001288 queue_delayed_work(hdev->req_workqueue,
1289 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001290 }
1291
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001292 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001293 goto failed;
1294 }
1295
1296 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1297 if (!cmd) {
1298 err = -ENOMEM;
1299 goto failed;
1300 }
1301
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001302 /* Cancel any potential discoverable timeout that might be
1303 * still active and store new timeout value. The arming of
1304 * the timeout happens in the complete handler.
1305 */
1306 cancel_delayed_work(&hdev->discov_off);
1307 hdev->discov_timeout = timeout;
1308
Johan Hedbergaed1a882015-11-22 17:24:44 +03001309 if (cp->val)
1310 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1311 else
1312 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1313
Johan Hedbergb456f872013-10-19 23:38:22 +03001314 /* Limited discoverable mode */
1315 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001316 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001317 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001318 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001319
Johan Hedbergaed1a882015-11-22 17:24:44 +03001320 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1321 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001322
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001323failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001324 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001325 return err;
1326}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001327
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001328void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001329{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001330 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001331
1332 BT_DBG("status 0x%02x", status);
1333
1334 hci_dev_lock(hdev);
1335
Johan Hedberg333ae952015-03-17 13:48:47 +02001336 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001337 if (!cmd)
1338 goto unlock;
1339
Johan Hedberg37438c12013-10-14 16:20:05 +03001340 if (status) {
1341 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001342 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001343 goto remove_cmd;
1344 }
1345
Johan Hedberg2b76f452013-03-15 17:07:04 -05001346 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001347 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001348
Johan Hedberg37438c12013-10-14 16:20:05 +03001349remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001350 mgmt_pending_remove(cmd);
1351
1352unlock:
1353 hci_dev_unlock(hdev);
1354}
1355
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001356static int set_connectable_update_settings(struct hci_dev *hdev,
1357 struct sock *sk, u8 val)
1358{
1359 bool changed = false;
1360 int err;
1361
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001362 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001363 changed = true;
1364
1365 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001366 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001367 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001368 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1369 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001370 }
1371
1372 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1373 if (err < 0)
1374 return err;
1375
Johan Hedberg562064e2014-07-08 16:35:34 +03001376 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001377 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001378 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001379 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001380 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001381
1382 return 0;
1383}
1384
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001385static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001386 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001387{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001388 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001389 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001390 int err;
1391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001393
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001394 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1395 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001396 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1397 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001398
Johan Hedberga7e80f22013-01-09 16:05:19 +02001399 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001400 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1401 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001402
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001403 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001404
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001405 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001406 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001407 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001408 }
1409
Johan Hedberg333ae952015-03-17 13:48:47 +02001410 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1411 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001412 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1413 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001414 goto failed;
1415 }
1416
Johan Hedberg73f22f62010-12-29 16:00:25 +02001417 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1418 if (!cmd) {
1419 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001420 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001421 }
1422
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001423 if (cp->val) {
1424 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1425 } else {
1426 if (hdev->discov_timeout > 0)
1427 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001428
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001429 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1430 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1431 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001432 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001433
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001434 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1435 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001436
1437failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001438 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001439 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001440}
1441
Johan Hedbergb2939472014-07-30 09:22:23 +03001442static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001443 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001444{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001445 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001446 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001447 int err;
1448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001450
Johan Hedberga7e80f22013-01-09 16:05:19 +02001451 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001452 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1453 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001454
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001455 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001456
1457 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001458 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001459 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001460 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001461
Johan Hedbergb2939472014-07-30 09:22:23 +03001462 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001463 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001464 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001465
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001466 if (changed) {
1467 /* In limited privacy mode the change of bondable mode
1468 * may affect the local advertising address.
1469 */
1470 if (hdev_is_powered(hdev) &&
1471 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1472 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1473 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1474 queue_work(hdev->req_workqueue,
1475 &hdev->discoverable_update);
1476
Marcel Holtmann55594352013-10-06 16:11:57 -07001477 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001478 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001479
Marcel Holtmann55594352013-10-06 16:11:57 -07001480unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001481 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001482 return err;
1483}
1484
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001485static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1486 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001487{
1488 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001489 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001490 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001491 int err;
1492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001493 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001494
Johan Hedberge6fe7982013-10-02 15:45:22 +03001495 status = mgmt_bredr_support(hdev);
1496 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001497 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1498 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001499
Johan Hedberga7e80f22013-01-09 16:05:19 +02001500 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001501 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1502 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001503
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001504 hci_dev_lock(hdev);
1505
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001506 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001507 bool changed = false;
1508
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001509 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001510 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001511 changed = true;
1512 }
1513
1514 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1515 if (err < 0)
1516 goto failed;
1517
1518 if (changed)
1519 err = new_settings(hdev, sk);
1520
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001521 goto failed;
1522 }
1523
Johan Hedberg333ae952015-03-17 13:48:47 +02001524 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001525 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1526 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001527 goto failed;
1528 }
1529
1530 val = !!cp->val;
1531
1532 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1533 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1534 goto failed;
1535 }
1536
1537 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1538 if (!cmd) {
1539 err = -ENOMEM;
1540 goto failed;
1541 }
1542
1543 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1544 if (err < 0) {
1545 mgmt_pending_remove(cmd);
1546 goto failed;
1547 }
1548
1549failed:
1550 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001551 return err;
1552}
1553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001554static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001555{
1556 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001557 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001558 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001559 int err;
1560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001562
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001563 status = mgmt_bredr_support(hdev);
1564 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001566
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001567 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001568 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1569 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001570
Johan Hedberga7e80f22013-01-09 16:05:19 +02001571 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1573 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001574
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001575 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001576
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001577 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001578 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001579
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001580 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001581 changed = !hci_dev_test_and_set_flag(hdev,
1582 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001583 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001584 changed = hci_dev_test_and_clear_flag(hdev,
1585 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001586 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001587 changed = hci_dev_test_and_clear_flag(hdev,
1588 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001589 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001590 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001591 }
1592
1593 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1594 if (err < 0)
1595 goto failed;
1596
1597 if (changed)
1598 err = new_settings(hdev, sk);
1599
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001600 goto failed;
1601 }
1602
Johan Hedberg333ae952015-03-17 13:48:47 +02001603 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001604 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1605 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001606 goto failed;
1607 }
1608
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001609 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001610 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1611 goto failed;
1612 }
1613
1614 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1615 if (!cmd) {
1616 err = -ENOMEM;
1617 goto failed;
1618 }
1619
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001620 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001621 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1622 sizeof(cp->val), &cp->val);
1623
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001624 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001625 if (err < 0) {
1626 mgmt_pending_remove(cmd);
1627 goto failed;
1628 }
1629
1630failed:
1631 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001632 return err;
1633}
1634
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001635static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001636{
1637 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001638 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001639 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001640 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001641
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001642 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001643
Johan Hedberge6fe7982013-10-02 15:45:22 +03001644 status = mgmt_bredr_support(hdev);
1645 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001646 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001647
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001648 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001649 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1650 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001651
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001652 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001653 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1654 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001655
Johan Hedberga7e80f22013-01-09 16:05:19 +02001656 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001657 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1658 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001659
Marcel Holtmannee392692013-10-01 22:59:23 -07001660 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001661
Johan Hedberg333ae952015-03-17 13:48:47 +02001662 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001663 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1664 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001665 goto unlock;
1666 }
1667
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001668 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001669 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001670 } else {
1671 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001672 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1673 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001674 goto unlock;
1675 }
1676
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001677 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001678 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001679
1680 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1681 if (err < 0)
1682 goto unlock;
1683
1684 if (changed)
1685 err = new_settings(hdev, sk);
1686
1687unlock:
1688 hci_dev_unlock(hdev);
1689 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001690}
1691
Marcel Holtmann1904a852015-01-11 13:50:44 -08001692static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001693{
1694 struct cmd_lookup match = { NULL, hdev };
1695
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301696 hci_dev_lock(hdev);
1697
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001698 if (status) {
1699 u8 mgmt_err = mgmt_status(status);
1700
1701 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1702 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301703 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001704 }
1705
1706 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1707
1708 new_settings(hdev, match.sk);
1709
1710 if (match.sk)
1711 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001712
1713 /* Make sure the controller has a good default for
1714 * advertising data. Restrict the update to when LE
1715 * has actually been enabled. During power on, the
1716 * update in powered_update_hci will take care of it.
1717 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001718 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001719 struct hci_request req;
1720
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001721 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001722 __hci_req_update_adv_data(&req, 0x00);
1723 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001724 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001725 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001726 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301727
1728unlock:
1729 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001730}
1731
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001732static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001733{
1734 struct mgmt_mode *cp = data;
1735 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001736 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001737 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001738 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001739 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001740
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001741 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001742
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001743 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001744 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1745 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001746
Johan Hedberga7e80f22013-01-09 16:05:19 +02001747 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001748 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1749 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001750
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001751 /* Bluetooth single mode LE only controllers or dual-mode
1752 * controllers configured as LE only devices, do not allow
1753 * switching LE off. These have either LE enabled explicitly
1754 * or BR/EDR has been previously switched off.
1755 *
1756 * When trying to enable an already enabled LE, then gracefully
1757 * send a positive response. Trying to disable it however will
1758 * result into rejection.
1759 */
1760 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1761 if (cp->val == 0x01)
1762 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1763
Johan Hedberga69e8372015-03-06 21:08:53 +02001764 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1765 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001766 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001767
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001768 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001769
1770 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001771 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001772
Florian Grandel847818d2015-06-18 03:16:46 +02001773 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001774 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001775
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001776 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001777 bool changed = false;
1778
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001779 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001780 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001781 changed = true;
1782 }
1783
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001784 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001785 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001786 changed = true;
1787 }
1788
Johan Hedberg06199cf2012-02-22 16:37:11 +02001789 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1790 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001791 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001792
1793 if (changed)
1794 err = new_settings(hdev, sk);
1795
Johan Hedberg1de028c2012-02-29 19:55:35 -08001796 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001797 }
1798
Johan Hedberg333ae952015-03-17 13:48:47 +02001799 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1800 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001801 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1802 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001803 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001804 }
1805
1806 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1807 if (!cmd) {
1808 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001809 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001810 }
1811
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001812 hci_req_init(&req, hdev);
1813
Johan Hedberg06199cf2012-02-22 16:37:11 +02001814 memset(&hci_cp, 0, sizeof(hci_cp));
1815
1816 if (val) {
1817 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001818 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001819 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001820 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001821 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001822 }
1823
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001824 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1825 &hci_cp);
1826
1827 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301828 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001829 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001830
Johan Hedberg1de028c2012-02-29 19:55:35 -08001831unlock:
1832 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001833 return err;
1834}
1835
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001836/* This is a helper function to test for pending mgmt commands that can
1837 * cause CoD or EIR HCI commands. We can only allow one such pending
1838 * mgmt command at a time since otherwise we cannot easily track what
1839 * the current values are, will be, and based on that calculate if a new
1840 * HCI command needs to be sent and if yes with what value.
1841 */
1842static bool pending_eir_or_class(struct hci_dev *hdev)
1843{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001844 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001845
1846 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1847 switch (cmd->opcode) {
1848 case MGMT_OP_ADD_UUID:
1849 case MGMT_OP_REMOVE_UUID:
1850 case MGMT_OP_SET_DEV_CLASS:
1851 case MGMT_OP_SET_POWERED:
1852 return true;
1853 }
1854 }
1855
1856 return false;
1857}
1858
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001859static const u8 bluetooth_base_uuid[] = {
1860 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1861 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1862};
1863
1864static u8 get_uuid_size(const u8 *uuid)
1865{
1866 u32 val;
1867
1868 if (memcmp(uuid, bluetooth_base_uuid, 12))
1869 return 128;
1870
1871 val = get_unaligned_le32(&uuid[12]);
1872 if (val > 0xffff)
1873 return 32;
1874
1875 return 16;
1876}
1877
Johan Hedberg92da6092013-03-15 17:06:55 -05001878static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1879{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001880 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001881
1882 hci_dev_lock(hdev);
1883
Johan Hedberg333ae952015-03-17 13:48:47 +02001884 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001885 if (!cmd)
1886 goto unlock;
1887
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001888 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1889 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001890
1891 mgmt_pending_remove(cmd);
1892
1893unlock:
1894 hci_dev_unlock(hdev);
1895}
1896
Marcel Holtmann1904a852015-01-11 13:50:44 -08001897static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001898{
1899 BT_DBG("status 0x%02x", status);
1900
1901 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1902}
1903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001905{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001906 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001907 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001908 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001909 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001910 int err;
1911
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001912 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001913
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001914 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001915
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001916 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001917 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1918 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001919 goto failed;
1920 }
1921
Andre Guedes92c4c202012-06-07 19:05:44 -03001922 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001923 if (!uuid) {
1924 err = -ENOMEM;
1925 goto failed;
1926 }
1927
1928 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001929 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001930 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001931
Johan Hedbergde66aa62013-01-27 00:31:27 +02001932 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001933
Johan Hedberg890ea892013-03-15 17:06:52 -05001934 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001935
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001936 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001937 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001938
Johan Hedberg92da6092013-03-15 17:06:55 -05001939 err = hci_req_run(&req, add_uuid_complete);
1940 if (err < 0) {
1941 if (err != -ENODATA)
1942 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001943
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001944 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1945 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001946 goto failed;
1947 }
1948
1949 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001950 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001951 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001952 goto failed;
1953 }
1954
1955 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001956
1957failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001958 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001959 return err;
1960}
1961
Johan Hedberg24b78d02012-02-23 23:24:30 +02001962static bool enable_service_cache(struct hci_dev *hdev)
1963{
1964 if (!hdev_is_powered(hdev))
1965 return false;
1966
Marcel Holtmann238be782015-03-13 02:11:06 -07001967 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001968 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1969 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001970 return true;
1971 }
1972
1973 return false;
1974}
1975
Marcel Holtmann1904a852015-01-11 13:50:44 -08001976static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001977{
1978 BT_DBG("status 0x%02x", status);
1979
1980 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1981}
1982
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001983static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001984 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001985{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001986 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001987 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001988 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001989 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 -05001990 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001991 int err, found;
1992
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001993 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001994
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001996
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001997 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001998 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1999 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002000 goto unlock;
2001 }
2002
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002003 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002004 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002005
Johan Hedberg24b78d02012-02-23 23:24:30 +02002006 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002007 err = mgmt_cmd_complete(sk, hdev->id,
2008 MGMT_OP_REMOVE_UUID,
2009 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002010 goto unlock;
2011 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002012
Johan Hedberg9246a862012-02-23 21:33:16 +02002013 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002014 }
2015
2016 found = 0;
2017
Johan Hedberg056341c2013-01-27 00:31:30 +02002018 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002019 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2020 continue;
2021
2022 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002023 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002024 found++;
2025 }
2026
2027 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002028 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2029 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002030 goto unlock;
2031 }
2032
Johan Hedberg9246a862012-02-23 21:33:16 +02002033update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002034 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002035
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002036 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002037 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002038
Johan Hedberg92da6092013-03-15 17:06:55 -05002039 err = hci_req_run(&req, remove_uuid_complete);
2040 if (err < 0) {
2041 if (err != -ENODATA)
2042 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002043
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002044 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2045 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002046 goto unlock;
2047 }
2048
2049 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002050 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002051 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002052 goto unlock;
2053 }
2054
2055 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002056
2057unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002058 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002059 return err;
2060}
2061
Marcel Holtmann1904a852015-01-11 13:50:44 -08002062static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002063{
2064 BT_DBG("status 0x%02x", status);
2065
2066 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2067}
2068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002069static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002070 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002071{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002072 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002073 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002074 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002075 int err;
2076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002077 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002078
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002079 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002080 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2081 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002082
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002083 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002084
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002085 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002086 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2087 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002088 goto unlock;
2089 }
2090
2091 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002092 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2093 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002094 goto unlock;
2095 }
2096
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002097 hdev->major_class = cp->major;
2098 hdev->minor_class = cp->minor;
2099
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002100 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002101 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2102 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002103 goto unlock;
2104 }
2105
Johan Hedberg890ea892013-03-15 17:06:52 -05002106 hci_req_init(&req, hdev);
2107
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002108 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002109 hci_dev_unlock(hdev);
2110 cancel_delayed_work_sync(&hdev->service_cache);
2111 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002112 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002113 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002114
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002115 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002116
Johan Hedberg92da6092013-03-15 17:06:55 -05002117 err = hci_req_run(&req, set_class_complete);
2118 if (err < 0) {
2119 if (err != -ENODATA)
2120 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002121
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002122 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2123 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002124 goto unlock;
2125 }
2126
2127 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002128 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002129 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002130 goto unlock;
2131 }
2132
2133 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002134
Johan Hedbergb5235a62012-02-21 14:32:24 +02002135unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002136 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002137 return err;
2138}
2139
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002140static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002141 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002142{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002143 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002144 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2145 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002146 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002147 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002148 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002149
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002150 BT_DBG("request for %s", hdev->name);
2151
2152 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002153 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2154 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002155
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002156 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002157 if (key_count > max_key_count) {
2158 BT_ERR("load_link_keys: too big key_count value %u",
2159 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002160 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2161 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002162 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002163
Johan Hedberg86742e12011-11-07 23:13:38 +02002164 expected_len = sizeof(*cp) + key_count *
2165 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002166 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002167 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002168 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002169 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2170 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002171 }
2172
Johan Hedberg4ae14302013-01-20 14:27:13 +02002173 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002174 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2175 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002178 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002179
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002180 for (i = 0; i < key_count; i++) {
2181 struct mgmt_link_key_info *key = &cp->keys[i];
2182
Marcel Holtmann8e991132014-01-10 02:07:25 -08002183 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002184 return mgmt_cmd_status(sk, hdev->id,
2185 MGMT_OP_LOAD_LINK_KEYS,
2186 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002187 }
2188
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002189 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002190
2191 hci_link_keys_clear(hdev);
2192
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002193 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002194 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002195 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002196 changed = hci_dev_test_and_clear_flag(hdev,
2197 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002198
2199 if (changed)
2200 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002201
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002202 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002203 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002204
Johan Hedberg58e92932014-06-24 14:00:26 +03002205 /* Always ignore debug keys and require a new pairing if
2206 * the user wants to use them.
2207 */
2208 if (key->type == HCI_LK_DEBUG_COMBINATION)
2209 continue;
2210
Johan Hedberg7652ff62014-06-24 13:15:49 +03002211 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2212 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002213 }
2214
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002215 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002216
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002217 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002218
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002219 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002220}
2221
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002222static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002223 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002224{
2225 struct mgmt_ev_device_unpaired ev;
2226
2227 bacpy(&ev.addr.bdaddr, bdaddr);
2228 ev.addr.type = addr_type;
2229
2230 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002232}
2233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002234static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002235 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002236{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002237 struct mgmt_cp_unpair_device *cp = data;
2238 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002239 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002240 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002241 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002242 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002243 int err;
2244
Johan Hedberga8a1d192011-11-10 15:54:38 +02002245 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002246 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2247 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002248
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002249 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002250 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2251 MGMT_STATUS_INVALID_PARAMS,
2252 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002253
Johan Hedberg118da702013-01-20 14:27:20 +02002254 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002255 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2256 MGMT_STATUS_INVALID_PARAMS,
2257 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002258
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002259 hci_dev_lock(hdev);
2260
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002261 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002262 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2263 MGMT_STATUS_NOT_POWERED, &rp,
2264 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002265 goto unlock;
2266 }
2267
Johan Hedberge0b2b272014-02-18 17:14:31 +02002268 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002269 /* If disconnection is requested, then look up the
2270 * connection. If the remote device is connected, it
2271 * will be later used to terminate the link.
2272 *
2273 * Setting it to NULL explicitly will cause no
2274 * termination of the link.
2275 */
2276 if (cp->disconnect)
2277 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2278 &cp->addr.bdaddr);
2279 else
2280 conn = NULL;
2281
Johan Hedberg124f6e32012-02-09 13:50:12 +02002282 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002283 if (err < 0) {
2284 err = mgmt_cmd_complete(sk, hdev->id,
2285 MGMT_OP_UNPAIR_DEVICE,
2286 MGMT_STATUS_NOT_PAIRED, &rp,
2287 sizeof(rp));
2288 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002289 }
2290
Johan Hedbergec182f02015-10-21 18:03:03 +03002291 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002292 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002293
Johan Hedbergec182f02015-10-21 18:03:03 +03002294 /* LE address type */
2295 addr_type = le_addr_type(cp->addr.type);
2296
2297 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2298
2299 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002300 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002301 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2302 MGMT_STATUS_NOT_PAIRED, &rp,
2303 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002304 goto unlock;
2305 }
2306
Johan Hedbergec182f02015-10-21 18:03:03 +03002307 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2308 if (!conn) {
2309 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2310 goto done;
2311 }
2312
Johan Hedbergc81d5552015-10-22 09:38:35 +03002313 /* Abort any ongoing SMP pairing */
2314 smp_cancel_pairing(conn);
2315
Johan Hedbergec182f02015-10-21 18:03:03 +03002316 /* Defer clearing up the connection parameters until closing to
2317 * give a chance of keeping them if a repairing happens.
2318 */
2319 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2320
Johan Hedbergfc643612015-10-22 09:38:31 +03002321 /* Disable auto-connection parameters if present */
2322 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2323 if (params) {
2324 if (params->explicit_connect)
2325 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2326 else
2327 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2328 }
2329
Johan Hedbergec182f02015-10-21 18:03:03 +03002330 /* If disconnection is not requested, then clear the connection
2331 * variable so that the link is not terminated.
2332 */
2333 if (!cp->disconnect)
2334 conn = NULL;
2335
2336done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002337 /* If the connection variable is set, then termination of the
2338 * link is requested.
2339 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002340 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002341 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2342 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002343 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002344 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002345 }
2346
Johan Hedberg124f6e32012-02-09 13:50:12 +02002347 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002348 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002349 if (!cmd) {
2350 err = -ENOMEM;
2351 goto unlock;
2352 }
2353
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002354 cmd->cmd_complete = addr_cmd_complete;
2355
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002356 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002357 if (err < 0)
2358 mgmt_pending_remove(cmd);
2359
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002362 return err;
2363}
2364
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002365static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002366 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002367{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002368 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002369 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002370 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372 int err;
2373
2374 BT_DBG("");
2375
Johan Hedberg06a63b12013-01-20 14:27:21 +02002376 memset(&rp, 0, sizeof(rp));
2377 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2378 rp.addr.type = cp->addr.type;
2379
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002380 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002381 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2382 MGMT_STATUS_INVALID_PARAMS,
2383 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002384
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002385 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002386
2387 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002388 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2389 MGMT_STATUS_NOT_POWERED, &rp,
2390 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002391 goto failed;
2392 }
2393
Johan Hedberg333ae952015-03-17 13:48:47 +02002394 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002395 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2396 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002397 goto failed;
2398 }
2399
Andre Guedes591f47f2012-04-24 21:02:49 -03002400 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002401 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2402 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002403 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002404 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2405 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002406
Vishal Agarwalf9607272012-06-13 05:32:43 +05302407 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002408 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2409 MGMT_STATUS_NOT_CONNECTED, &rp,
2410 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002411 goto failed;
2412 }
2413
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002414 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002415 if (!cmd) {
2416 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002417 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002418 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002419
Johan Hedbergf5818c22014-12-05 13:36:02 +02002420 cmd->cmd_complete = generic_cmd_complete;
2421
Johan Hedberge3f2f922014-08-18 20:33:33 +03002422 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002423 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002424 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002425
2426failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002427 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002428 return err;
2429}
2430
Andre Guedes57c14772012-04-24 21:02:50 -03002431static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002432{
2433 switch (link_type) {
2434 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002435 switch (addr_type) {
2436 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002437 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002438
Johan Hedberg48264f02011-11-09 13:58:58 +02002439 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002440 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002441 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002442 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002443
Johan Hedberg4c659c32011-11-07 23:13:39 +02002444 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002445 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002446 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002447 }
2448}
2449
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002450static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2451 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002452{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002453 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002454 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002455 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002456 int err;
2457 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002458
2459 BT_DBG("");
2460
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002461 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002462
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002463 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002464 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2465 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002466 goto unlock;
2467 }
2468
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002469 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002470 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2471 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002472 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002473 }
2474
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002475 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002476 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002477 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002478 err = -ENOMEM;
2479 goto unlock;
2480 }
2481
Johan Hedberg2784eb42011-01-21 13:56:35 +02002482 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002483 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002484 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2485 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002486 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002487 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002488 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002489 continue;
2490 i++;
2491 }
2492
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002493 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002494
Johan Hedberg4c659c32011-11-07 23:13:39 +02002495 /* Recalculate length in case of filtered SCO connections, etc */
2496 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002497
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002498 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2499 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002500
Johan Hedberga38528f2011-01-22 06:46:43 +02002501 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002502
2503unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002504 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002505 return err;
2506}
2507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002508static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002509 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002510{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002511 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002512 int err;
2513
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002514 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002515 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002516 if (!cmd)
2517 return -ENOMEM;
2518
Johan Hedbergd8457692012-02-17 14:24:57 +02002519 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002520 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002521 if (err < 0)
2522 mgmt_pending_remove(cmd);
2523
2524 return err;
2525}
2526
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002527static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002529{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002530 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002531 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002532 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002533 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002534 int err;
2535
2536 BT_DBG("");
2537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002539
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002540 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002541 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2542 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002543 goto failed;
2544 }
2545
Johan Hedbergd8457692012-02-17 14:24:57 +02002546 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002547 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002548 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2549 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002550 goto failed;
2551 }
2552
2553 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002554 struct mgmt_cp_pin_code_neg_reply ncp;
2555
2556 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002557
2558 BT_ERR("PIN code is not 16 bytes long");
2559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002560 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002561 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002562 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2563 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002564
2565 goto failed;
2566 }
2567
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002568 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002569 if (!cmd) {
2570 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002571 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002572 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002573
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002574 cmd->cmd_complete = addr_cmd_complete;
2575
Johan Hedbergd8457692012-02-17 14:24:57 +02002576 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002577 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002578 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002579
2580 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2581 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002582 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002583
2584failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002585 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002586 return err;
2587}
2588
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2590 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002591{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002592 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002593
2594 BT_DBG("");
2595
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002596 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002597 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2598 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002599
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002600 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002601
2602 hdev->io_capability = cp->io_capability;
2603
2604 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002605 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002606
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002607 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002608
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002609 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2610 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002611}
2612
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002613static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002614{
2615 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002616 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002617
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002618 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002619 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2620 continue;
2621
Johan Hedberge9a416b2011-02-19 12:05:56 -03002622 if (cmd->user_data != conn)
2623 continue;
2624
2625 return cmd;
2626 }
2627
2628 return NULL;
2629}
2630
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002631static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002632{
2633 struct mgmt_rp_pair_device rp;
2634 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002635 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002636
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002637 bacpy(&rp.addr.bdaddr, &conn->dst);
2638 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002639
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002640 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2641 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642
2643 /* So we don't get further callbacks for this connection */
2644 conn->connect_cfm_cb = NULL;
2645 conn->security_cfm_cb = NULL;
2646 conn->disconn_cfm_cb = NULL;
2647
David Herrmann76a68ba2013-04-06 20:28:37 +02002648 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002649
2650 /* The device is paired so there is no need to remove
2651 * its connection parameters anymore.
2652 */
2653 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002654
2655 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002656
2657 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002658}
2659
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002660void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2661{
2662 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002663 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002664
2665 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002666 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002667 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002668 mgmt_pending_remove(cmd);
2669 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002670}
2671
Johan Hedberge9a416b2011-02-19 12:05:56 -03002672static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2673{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002674 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002675
2676 BT_DBG("status %u", status);
2677
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002678 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002679 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002680 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002681 return;
2682 }
2683
2684 cmd->cmd_complete(cmd, mgmt_status(status));
2685 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002686}
2687
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002688static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302689{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002690 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302691
2692 BT_DBG("status %u", status);
2693
2694 if (!status)
2695 return;
2696
2697 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002698 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302699 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);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302705}
2706
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002707static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002708 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002709{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002710 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002711 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002712 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002713 u8 sec_level, auth_type;
2714 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002715 int err;
2716
2717 BT_DBG("");
2718
Szymon Jancf950a30e2013-01-18 12:48:07 +01002719 memset(&rp, 0, sizeof(rp));
2720 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2721 rp.addr.type = cp->addr.type;
2722
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002723 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002724 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2725 MGMT_STATUS_INVALID_PARAMS,
2726 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002727
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002728 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002729 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2730 MGMT_STATUS_INVALID_PARAMS,
2731 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002732
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002733 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002734
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002735 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002736 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2737 MGMT_STATUS_NOT_POWERED, &rp,
2738 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002739 goto unlock;
2740 }
2741
Johan Hedberg55e76b32015-03-10 22:34:40 +02002742 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2743 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2744 MGMT_STATUS_ALREADY_PAIRED, &rp,
2745 sizeof(rp));
2746 goto unlock;
2747 }
2748
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002749 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002750 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002751
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002752 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002753 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2754 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002755 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002756 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002757 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002758
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002759 /* When pairing a new device, it is expected to remember
2760 * this device for future connections. Adding the connection
2761 * parameter information ahead of time allows tracking
2762 * of the slave preferred values and will speed up any
2763 * further connection establishment.
2764 *
2765 * If connection parameters already exist, then they
2766 * will be kept and this function does nothing.
2767 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002768 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2769
2770 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2771 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002772
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002773 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2774 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002775 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002776 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002777
Ville Tervo30e76272011-02-22 16:10:53 -03002778 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002779 int status;
2780
2781 if (PTR_ERR(conn) == -EBUSY)
2782 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002783 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2784 status = MGMT_STATUS_NOT_SUPPORTED;
2785 else if (PTR_ERR(conn) == -ECONNREFUSED)
2786 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002787 else
2788 status = MGMT_STATUS_CONNECT_FAILED;
2789
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002790 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2791 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002792 goto unlock;
2793 }
2794
2795 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002796 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002797 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2798 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002799 goto unlock;
2800 }
2801
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002802 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002803 if (!cmd) {
2804 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002805 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002806 goto unlock;
2807 }
2808
Johan Hedberg04ab2742014-12-05 13:36:04 +02002809 cmd->cmd_complete = pairing_complete;
2810
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002811 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002812 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002813 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002814 conn->security_cfm_cb = pairing_complete_cb;
2815 conn->disconn_cfm_cb = pairing_complete_cb;
2816 } else {
2817 conn->connect_cfm_cb = le_pairing_complete_cb;
2818 conn->security_cfm_cb = le_pairing_complete_cb;
2819 conn->disconn_cfm_cb = le_pairing_complete_cb;
2820 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002821
Johan Hedberge9a416b2011-02-19 12:05:56 -03002822 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002823 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002824
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002825 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002826 hci_conn_security(conn, sec_level, auth_type, true)) {
2827 cmd->cmd_complete(cmd, 0);
2828 mgmt_pending_remove(cmd);
2829 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002830
2831 err = 0;
2832
2833unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002834 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002835 return err;
2836}
2837
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002838static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2839 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002840{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002841 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002842 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002843 struct hci_conn *conn;
2844 int err;
2845
2846 BT_DBG("");
2847
Johan Hedberg28424702012-02-02 04:02:29 +02002848 hci_dev_lock(hdev);
2849
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002850 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002851 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2852 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002853 goto unlock;
2854 }
2855
Johan Hedberg333ae952015-03-17 13:48:47 +02002856 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002857 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002858 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2859 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002860 goto unlock;
2861 }
2862
2863 conn = cmd->user_data;
2864
2865 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002866 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2867 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002868 goto unlock;
2869 }
2870
Johan Hedberga511b352014-12-11 21:45:45 +02002871 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2872 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002873
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002874 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2875 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002876unlock:
2877 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002878 return err;
2879}
2880
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002881static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002882 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002883 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002884{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002885 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002886 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002887 int err;
2888
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002889 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002890
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002891 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002892 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2893 MGMT_STATUS_NOT_POWERED, addr,
2894 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002895 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002896 }
2897
Johan Hedberg1707c602013-03-15 17:07:15 -05002898 if (addr->type == BDADDR_BREDR)
2899 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002900 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002901 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2902 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002903
Johan Hedberg272d90d2012-02-09 15:26:12 +02002904 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002905 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2906 MGMT_STATUS_NOT_CONNECTED, addr,
2907 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002908 goto done;
2909 }
2910
Johan Hedberg1707c602013-03-15 17:07:15 -05002911 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002912 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002913 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002914 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2915 MGMT_STATUS_SUCCESS, addr,
2916 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002917 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002918 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2919 MGMT_STATUS_FAILED, addr,
2920 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002921
Brian Gix47c15e22011-11-16 13:53:14 -08002922 goto done;
2923 }
2924
Johan Hedberg1707c602013-03-15 17:07:15 -05002925 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002926 if (!cmd) {
2927 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002928 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002929 }
2930
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002931 cmd->cmd_complete = addr_cmd_complete;
2932
Brian Gix0df4c182011-11-16 13:53:13 -08002933 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002934 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2935 struct hci_cp_user_passkey_reply cp;
2936
Johan Hedberg1707c602013-03-15 17:07:15 -05002937 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002938 cp.passkey = passkey;
2939 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2940 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002941 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2942 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002943
Johan Hedberga664b5b2011-02-19 12:06:02 -03002944 if (err < 0)
2945 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002946
Brian Gix0df4c182011-11-16 13:53:13 -08002947done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002948 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002949 return err;
2950}
2951
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302952static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2953 void *data, u16 len)
2954{
2955 struct mgmt_cp_pin_code_neg_reply *cp = data;
2956
2957 BT_DBG("");
2958
Johan Hedberg1707c602013-03-15 17:07:15 -05002959 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302960 MGMT_OP_PIN_CODE_NEG_REPLY,
2961 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2962}
2963
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002964static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2965 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002966{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002967 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002968
2969 BT_DBG("");
2970
2971 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002972 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2973 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002974
Johan Hedberg1707c602013-03-15 17:07:15 -05002975 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002976 MGMT_OP_USER_CONFIRM_REPLY,
2977 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002978}
2979
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002980static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002981 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002982{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002983 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002984
2985 BT_DBG("");
2986
Johan Hedberg1707c602013-03-15 17:07:15 -05002987 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002988 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2989 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002990}
2991
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002992static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2993 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002994{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002995 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002996
2997 BT_DBG("");
2998
Johan Hedberg1707c602013-03-15 17:07:15 -05002999 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003000 MGMT_OP_USER_PASSKEY_REPLY,
3001 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003002}
3003
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003004static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003006{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003007 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003008
3009 BT_DBG("");
3010
Johan Hedberg1707c602013-03-15 17:07:15 -05003011 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3013 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003014}
3015
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003016static void adv_expire(struct hci_dev *hdev, u32 flags)
3017{
3018 struct adv_info *adv_instance;
3019 struct hci_request req;
3020 int err;
3021
3022 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3023 if (!adv_instance)
3024 return;
3025
3026 /* stop if current instance doesn't need to be changed */
3027 if (!(adv_instance->flags & flags))
3028 return;
3029
3030 cancel_adv_timeout(hdev);
3031
3032 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3033 if (!adv_instance)
3034 return;
3035
3036 hci_req_init(&req, hdev);
3037 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3038 true);
3039 if (err)
3040 return;
3041
3042 hci_req_run(&req, NULL);
3043}
3044
Marcel Holtmann1904a852015-01-11 13:50:44 -08003045static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003046{
3047 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003048 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003049
3050 BT_DBG("status 0x%02x", status);
3051
3052 hci_dev_lock(hdev);
3053
Johan Hedberg333ae952015-03-17 13:48:47 +02003054 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003055 if (!cmd)
3056 goto unlock;
3057
3058 cp = cmd->param;
3059
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003060 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003061 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3062 mgmt_status(status));
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003063 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003064 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3065 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003066
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02003067 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3068 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3069 }
3070
Johan Hedberg13928972013-03-15 17:07:00 -05003071 mgmt_pending_remove(cmd);
3072
3073unlock:
3074 hci_dev_unlock(hdev);
3075}
3076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003077static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003078 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003079{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003080 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003081 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003082 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003083 int err;
3084
3085 BT_DBG("");
3086
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003087 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003088
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003089 /* If the old values are the same as the new ones just return a
3090 * direct command complete event.
3091 */
3092 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3093 !memcmp(hdev->short_name, cp->short_name,
3094 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003095 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3096 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003097 goto failed;
3098 }
3099
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003100 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003101
Johan Hedbergb5235a62012-02-21 14:32:24 +02003102 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003103 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003104
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003105 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3106 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003107 if (err < 0)
3108 goto failed;
3109
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003110 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3111 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003112 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003113
Johan Hedbergb5235a62012-02-21 14:32:24 +02003114 goto failed;
3115 }
3116
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003117 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003118 if (!cmd) {
3119 err = -ENOMEM;
3120 goto failed;
3121 }
3122
Johan Hedberg13928972013-03-15 17:07:00 -05003123 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3124
Johan Hedberg890ea892013-03-15 17:06:52 -05003125 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003126
3127 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003128 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003129 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003130 }
3131
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003132 /* The name is stored in the scan response data and so
3133 * no need to udpate the advertising data here.
3134 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003135 if (lmp_le_capable(hdev))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003136 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003137
Johan Hedberg13928972013-03-15 17:07:00 -05003138 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003139 if (err < 0)
3140 mgmt_pending_remove(cmd);
3141
3142failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003143 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003144 return err;
3145}
3146
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02003147static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
3148 u16 len)
3149{
3150 struct mgmt_cp_set_appearance *cp = data;
3151 u16 apperance;
3152 int err;
3153
3154 BT_DBG("");
3155
3156 apperance = le16_to_cpu(cp->appearance);
3157
3158 hci_dev_lock(hdev);
3159
3160 if (hdev->appearance != apperance) {
3161 hdev->appearance = apperance;
3162
3163 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3164 adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
3165 }
3166
3167 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
3168 0);
3169
3170 hci_dev_unlock(hdev);
3171
3172 return err;
3173}
3174
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003175static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3176 u16 opcode, struct sk_buff *skb)
3177{
3178 struct mgmt_rp_read_local_oob_data mgmt_rp;
3179 size_t rp_size = sizeof(mgmt_rp);
3180 struct mgmt_pending_cmd *cmd;
3181
3182 BT_DBG("%s status %u", hdev->name, status);
3183
3184 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3185 if (!cmd)
3186 return;
3187
3188 if (status || !skb) {
3189 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3190 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3191 goto remove;
3192 }
3193
3194 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3195
3196 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3197 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3198
3199 if (skb->len < sizeof(*rp)) {
3200 mgmt_cmd_status(cmd->sk, hdev->id,
3201 MGMT_OP_READ_LOCAL_OOB_DATA,
3202 MGMT_STATUS_FAILED);
3203 goto remove;
3204 }
3205
3206 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3207 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3208
3209 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3210 } else {
3211 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3212
3213 if (skb->len < sizeof(*rp)) {
3214 mgmt_cmd_status(cmd->sk, hdev->id,
3215 MGMT_OP_READ_LOCAL_OOB_DATA,
3216 MGMT_STATUS_FAILED);
3217 goto remove;
3218 }
3219
3220 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3221 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3222
3223 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3224 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3225 }
3226
3227 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3228 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3229
3230remove:
3231 mgmt_pending_remove(cmd);
3232}
3233
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003234static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003235 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003236{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003237 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003238 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003239 int err;
3240
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003241 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003242
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003243 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003244
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003245 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003246 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3247 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003248 goto unlock;
3249 }
3250
Andre Guedes9a1a1992012-07-24 15:03:48 -03003251 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003252 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3253 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003254 goto unlock;
3255 }
3256
Johan Hedberg333ae952015-03-17 13:48:47 +02003257 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003258 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3259 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003260 goto unlock;
3261 }
3262
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003263 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003264 if (!cmd) {
3265 err = -ENOMEM;
3266 goto unlock;
3267 }
3268
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003269 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003270
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003271 if (bredr_sc_enabled(hdev))
3272 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3273 else
3274 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3275
3276 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003277 if (err < 0)
3278 mgmt_pending_remove(cmd);
3279
3280unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003281 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003282 return err;
3283}
3284
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003285static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003286 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003287{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003288 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003289 int err;
3290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003291 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003292
Johan Hedberg5d57e792015-01-23 10:10:38 +02003293 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003294 return mgmt_cmd_complete(sk, hdev->id,
3295 MGMT_OP_ADD_REMOTE_OOB_DATA,
3296 MGMT_STATUS_INVALID_PARAMS,
3297 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003298
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003299 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003300
Marcel Holtmannec109112014-01-10 02:07:30 -08003301 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3302 struct mgmt_cp_add_remote_oob_data *cp = data;
3303 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003304
Johan Hedbergc19a4952014-11-17 20:52:19 +02003305 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003306 err = mgmt_cmd_complete(sk, hdev->id,
3307 MGMT_OP_ADD_REMOTE_OOB_DATA,
3308 MGMT_STATUS_INVALID_PARAMS,
3309 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003310 goto unlock;
3311 }
3312
Marcel Holtmannec109112014-01-10 02:07:30 -08003313 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003314 cp->addr.type, cp->hash,
3315 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003316 if (err < 0)
3317 status = MGMT_STATUS_FAILED;
3318 else
3319 status = MGMT_STATUS_SUCCESS;
3320
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003321 err = mgmt_cmd_complete(sk, hdev->id,
3322 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3323 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003324 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3325 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003326 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003327 u8 status;
3328
Johan Hedberg86df9202014-10-26 20:52:27 +01003329 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003330 /* Enforce zero-valued 192-bit parameters as
3331 * long as legacy SMP OOB isn't implemented.
3332 */
3333 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3334 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003335 err = mgmt_cmd_complete(sk, hdev->id,
3336 MGMT_OP_ADD_REMOTE_OOB_DATA,
3337 MGMT_STATUS_INVALID_PARAMS,
3338 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003339 goto unlock;
3340 }
3341
Johan Hedberg86df9202014-10-26 20:52:27 +01003342 rand192 = NULL;
3343 hash192 = NULL;
3344 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003345 /* In case one of the P-192 values is set to zero,
3346 * then just disable OOB data for P-192.
3347 */
3348 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3349 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3350 rand192 = NULL;
3351 hash192 = NULL;
3352 } else {
3353 rand192 = cp->rand192;
3354 hash192 = cp->hash192;
3355 }
3356 }
3357
3358 /* In case one of the P-256 values is set to zero, then just
3359 * disable OOB data for P-256.
3360 */
3361 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3362 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3363 rand256 = NULL;
3364 hash256 = NULL;
3365 } else {
3366 rand256 = cp->rand256;
3367 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003368 }
3369
Johan Hedberg81328d52014-10-26 20:33:47 +01003370 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003371 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003372 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003373 if (err < 0)
3374 status = MGMT_STATUS_FAILED;
3375 else
3376 status = MGMT_STATUS_SUCCESS;
3377
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003378 err = mgmt_cmd_complete(sk, hdev->id,
3379 MGMT_OP_ADD_REMOTE_OOB_DATA,
3380 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003381 } else {
3382 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003383 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3384 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003385 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003386
Johan Hedbergc19a4952014-11-17 20:52:19 +02003387unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003388 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003389 return err;
3390}
3391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003393 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003394{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003395 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003396 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003397 int err;
3398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003399 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003400
Johan Hedbergc19a4952014-11-17 20:52:19 +02003401 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003402 return mgmt_cmd_complete(sk, hdev->id,
3403 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3404 MGMT_STATUS_INVALID_PARAMS,
3405 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003406
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003407 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003408
Johan Hedbergeedbd582014-11-15 09:34:23 +02003409 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3410 hci_remote_oob_data_clear(hdev);
3411 status = MGMT_STATUS_SUCCESS;
3412 goto done;
3413 }
3414
Johan Hedberg6928a922014-10-26 20:46:09 +01003415 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003416 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003417 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003418 else
Szymon Janca6785be2012-12-13 15:11:21 +01003419 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003420
Johan Hedbergeedbd582014-11-15 09:34:23 +02003421done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003422 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3423 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003424
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003425 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003426 return err;
3427}
3428
Johan Hedberge68f0722015-11-11 08:30:30 +02003429void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003430{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003431 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003432
Andre Guedes7c307722013-04-30 15:29:28 -03003433 BT_DBG("status %d", status);
3434
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003435 hci_dev_lock(hdev);
3436
Johan Hedberg333ae952015-03-17 13:48:47 +02003437 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003438 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003439 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003440
Johan Hedberg78b781c2016-01-05 13:19:32 +02003441 if (!cmd)
3442 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3443
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003444 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003445 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003446 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003447 }
3448
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003449 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003450}
3451
Johan Hedberg591752a2015-11-11 08:11:24 +02003452static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3453 uint8_t *mgmt_status)
3454{
3455 switch (type) {
3456 case DISCOV_TYPE_LE:
3457 *mgmt_status = mgmt_le_support(hdev);
3458 if (*mgmt_status)
3459 return false;
3460 break;
3461 case DISCOV_TYPE_INTERLEAVED:
3462 *mgmt_status = mgmt_le_support(hdev);
3463 if (*mgmt_status)
3464 return false;
3465 /* Intentional fall-through */
3466 case DISCOV_TYPE_BREDR:
3467 *mgmt_status = mgmt_bredr_support(hdev);
3468 if (*mgmt_status)
3469 return false;
3470 break;
3471 default:
3472 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3473 return false;
3474 }
3475
3476 return true;
3477}
3478
Johan Hedberg78b781c2016-01-05 13:19:32 +02003479static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3480 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003481{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003482 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003483 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003484 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003485 int err;
3486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003487 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003488
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003489 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003490
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003491 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003492 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003493 MGMT_STATUS_NOT_POWERED,
3494 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003495 goto failed;
3496 }
3497
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003498 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003499 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003500 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3501 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003502 goto failed;
3503 }
3504
Johan Hedberg591752a2015-11-11 08:11:24 +02003505 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003506 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3507 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003508 goto failed;
3509 }
3510
Marcel Holtmann22078802014-12-05 11:45:22 +01003511 /* Clear the discovery filter first to free any previously
3512 * allocated memory for the UUID list.
3513 */
3514 hci_discovery_filter_clear(hdev);
3515
Andre Guedes4aab14e2012-02-17 20:39:36 -03003516 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003517 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003518 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3519 hdev->discovery.limited = true;
3520 else
3521 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003522
Johan Hedberg78b781c2016-01-05 13:19:32 +02003523 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003524 if (!cmd) {
3525 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003526 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003527 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003528
Johan Hedberge68f0722015-11-11 08:30:30 +02003529 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003530
3531 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003532 queue_work(hdev->req_workqueue, &hdev->discov_update);
3533 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003534
3535failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003536 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003537 return err;
3538}
3539
Johan Hedberg78b781c2016-01-05 13:19:32 +02003540static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3541 void *data, u16 len)
3542{
3543 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3544 data, len);
3545}
3546
3547static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3548 void *data, u16 len)
3549{
3550 return start_discovery_internal(sk, hdev,
3551 MGMT_OP_START_LIMITED_DISCOVERY,
3552 data, len);
3553}
3554
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003555static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3556 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003557{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003558 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3559 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003560}
3561
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003562static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3563 void *data, u16 len)
3564{
3565 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003566 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003567 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3568 u16 uuid_count, expected_len;
3569 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003570 int err;
3571
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003572 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003573
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003574 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003575
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003576 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003577 err = mgmt_cmd_complete(sk, hdev->id,
3578 MGMT_OP_START_SERVICE_DISCOVERY,
3579 MGMT_STATUS_NOT_POWERED,
3580 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003581 goto failed;
3582 }
3583
3584 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003585 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003586 err = mgmt_cmd_complete(sk, hdev->id,
3587 MGMT_OP_START_SERVICE_DISCOVERY,
3588 MGMT_STATUS_BUSY, &cp->type,
3589 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003590 goto failed;
3591 }
3592
3593 uuid_count = __le16_to_cpu(cp->uuid_count);
3594 if (uuid_count > max_uuid_count) {
3595 BT_ERR("service_discovery: too big uuid_count value %u",
3596 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003597 err = mgmt_cmd_complete(sk, hdev->id,
3598 MGMT_OP_START_SERVICE_DISCOVERY,
3599 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3600 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003601 goto failed;
3602 }
3603
3604 expected_len = sizeof(*cp) + uuid_count * 16;
3605 if (expected_len != len) {
3606 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3607 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003608 err = mgmt_cmd_complete(sk, hdev->id,
3609 MGMT_OP_START_SERVICE_DISCOVERY,
3610 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3611 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003612 goto failed;
3613 }
3614
Johan Hedberg591752a2015-11-11 08:11:24 +02003615 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3616 err = mgmt_cmd_complete(sk, hdev->id,
3617 MGMT_OP_START_SERVICE_DISCOVERY,
3618 status, &cp->type, sizeof(cp->type));
3619 goto failed;
3620 }
3621
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003622 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003623 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003624 if (!cmd) {
3625 err = -ENOMEM;
3626 goto failed;
3627 }
3628
Johan Hedberg2922a942014-12-05 13:36:06 +02003629 cmd->cmd_complete = service_discovery_cmd_complete;
3630
Marcel Holtmann22078802014-12-05 11:45:22 +01003631 /* Clear the discovery filter first to free any previously
3632 * allocated memory for the UUID list.
3633 */
3634 hci_discovery_filter_clear(hdev);
3635
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003636 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003637 hdev->discovery.type = cp->type;
3638 hdev->discovery.rssi = cp->rssi;
3639 hdev->discovery.uuid_count = uuid_count;
3640
3641 if (uuid_count > 0) {
3642 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3643 GFP_KERNEL);
3644 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003645 err = mgmt_cmd_complete(sk, hdev->id,
3646 MGMT_OP_START_SERVICE_DISCOVERY,
3647 MGMT_STATUS_FAILED,
3648 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003649 mgmt_pending_remove(cmd);
3650 goto failed;
3651 }
3652 }
3653
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003654 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003655 queue_work(hdev->req_workqueue, &hdev->discov_update);
3656 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003657
3658failed:
3659 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003660 return err;
3661}
3662
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003663void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003664{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003665 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003666
Andre Guedes0e05bba2013-04-30 15:29:33 -03003667 BT_DBG("status %d", status);
3668
3669 hci_dev_lock(hdev);
3670
Johan Hedberg333ae952015-03-17 13:48:47 +02003671 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003672 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003673 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003674 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003675 }
3676
Andre Guedes0e05bba2013-04-30 15:29:33 -03003677 hci_dev_unlock(hdev);
3678}
3679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003680static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003681 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003682{
Johan Hedbergd9306502012-02-20 23:25:18 +02003683 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003684 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003685 int err;
3686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003687 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003689 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003690
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003691 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003692 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3693 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3694 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003695 goto unlock;
3696 }
3697
3698 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003699 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3700 MGMT_STATUS_INVALID_PARAMS,
3701 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003702 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003703 }
3704
Johan Hedberg2922a942014-12-05 13:36:06 +02003705 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003706 if (!cmd) {
3707 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003708 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003709 }
3710
Johan Hedberg2922a942014-12-05 13:36:06 +02003711 cmd->cmd_complete = generic_cmd_complete;
3712
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003713 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3714 queue_work(hdev->req_workqueue, &hdev->discov_update);
3715 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003716
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003717unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003718 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003719 return err;
3720}
3721
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003722static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003723 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003724{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003725 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003726 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003727 int err;
3728
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003729 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003730
Johan Hedberg561aafb2012-01-04 13:31:59 +02003731 hci_dev_lock(hdev);
3732
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003733 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003734 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3735 MGMT_STATUS_FAILED, &cp->addr,
3736 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003737 goto failed;
3738 }
3739
Johan Hedberga198e7b2012-02-17 14:27:06 +02003740 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003741 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003742 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3743 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3744 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003745 goto failed;
3746 }
3747
3748 if (cp->name_known) {
3749 e->name_state = NAME_KNOWN;
3750 list_del(&e->list);
3751 } else {
3752 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003753 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003754 }
3755
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003756 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3757 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003758
3759failed:
3760 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003761 return err;
3762}
3763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003764static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003765 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003766{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003767 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003768 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003769 int err;
3770
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003771 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003772
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003773 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003774 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3775 MGMT_STATUS_INVALID_PARAMS,
3776 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003777
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003778 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003779
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003780 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3781 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003782 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003783 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003784 goto done;
3785 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003786
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003787 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3788 sk);
3789 status = MGMT_STATUS_SUCCESS;
3790
3791done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003792 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3793 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003794
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003795 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003796
3797 return err;
3798}
3799
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003800static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003801 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003802{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003803 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003804 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003805 int err;
3806
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003807 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003808
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003809 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003810 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3811 MGMT_STATUS_INVALID_PARAMS,
3812 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003813
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003814 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003815
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003816 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3817 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003818 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003819 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003820 goto done;
3821 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003822
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003823 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3824 sk);
3825 status = MGMT_STATUS_SUCCESS;
3826
3827done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003828 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3829 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003830
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003831 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003832
3833 return err;
3834}
3835
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003836static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3837 u16 len)
3838{
3839 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003840 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003841 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003842 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003843
3844 BT_DBG("%s", hdev->name);
3845
Szymon Jancc72d4b82012-03-16 16:02:57 +01003846 source = __le16_to_cpu(cp->source);
3847
3848 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003849 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3850 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003851
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003852 hci_dev_lock(hdev);
3853
Szymon Jancc72d4b82012-03-16 16:02:57 +01003854 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003855 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3856 hdev->devid_product = __le16_to_cpu(cp->product);
3857 hdev->devid_version = __le16_to_cpu(cp->version);
3858
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003859 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3860 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003861
Johan Hedberg890ea892013-03-15 17:06:52 -05003862 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003863 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003864 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003865
3866 hci_dev_unlock(hdev);
3867
3868 return err;
3869}
3870
Arman Uguray24b4f382015-03-23 15:57:12 -07003871static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3872 u16 opcode)
3873{
3874 BT_DBG("status %d", status);
3875}
3876
Marcel Holtmann1904a852015-01-11 13:50:44 -08003877static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3878 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003879{
3880 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003881 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003882 u8 instance;
3883 struct adv_info *adv_instance;
3884 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003885
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303886 hci_dev_lock(hdev);
3887
Johan Hedberg4375f102013-09-25 13:26:10 +03003888 if (status) {
3889 u8 mgmt_err = mgmt_status(status);
3890
3891 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3892 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303893 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003894 }
3895
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003896 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003897 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003898 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003899 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003900
Johan Hedberg4375f102013-09-25 13:26:10 +03003901 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3902 &match);
3903
3904 new_settings(hdev, match.sk);
3905
3906 if (match.sk)
3907 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303908
Arman Uguray24b4f382015-03-23 15:57:12 -07003909 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003910 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003911 */
3912 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003913 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003914 goto unlock;
3915
Florian Grandel7816b822015-06-18 03:16:45 +02003916 instance = hdev->cur_adv_instance;
3917 if (!instance) {
3918 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3919 struct adv_info, list);
3920 if (!adv_instance)
3921 goto unlock;
3922
3923 instance = adv_instance->instance;
3924 }
3925
Arman Uguray24b4f382015-03-23 15:57:12 -07003926 hci_req_init(&req, hdev);
3927
Johan Hedbergf2252572015-11-18 12:49:20 +02003928 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003929
Florian Grandel7816b822015-06-18 03:16:45 +02003930 if (!err)
3931 err = hci_req_run(&req, enable_advertising_instance);
3932
3933 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003934 BT_ERR("Failed to re-configure advertising");
3935
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303936unlock:
3937 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003938}
3939
Marcel Holtmann21b51872013-10-10 09:47:53 -07003940static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3941 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003942{
3943 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003944 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003945 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003946 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003947 int err;
3948
3949 BT_DBG("request for %s", hdev->name);
3950
Johan Hedberge6fe7982013-10-02 15:45:22 +03003951 status = mgmt_le_support(hdev);
3952 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003953 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3954 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003955
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003956 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003957 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003959
3960 hci_dev_lock(hdev);
3961
3962 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003963
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003964 /* The following conditions are ones which mean that we should
3965 * not do any HCI communication but directly send a mgmt
3966 * response to user space (after toggling the flag if
3967 * necessary).
3968 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003969 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003970 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3971 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003972 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003973 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003974 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003975 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003976
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003977 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003978 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07003979 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003980 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003981 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003982 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003983 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003984 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003985 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003986 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003987 }
3988
3989 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3990 if (err < 0)
3991 goto unlock;
3992
3993 if (changed)
3994 err = new_settings(hdev, sk);
3995
3996 goto unlock;
3997 }
3998
Johan Hedberg333ae952015-03-17 13:48:47 +02003999 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4000 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004001 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4002 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004003 goto unlock;
4004 }
4005
4006 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4007 if (!cmd) {
4008 err = -ENOMEM;
4009 goto unlock;
4010 }
4011
4012 hci_req_init(&req, hdev);
4013
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004014 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004015 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004016 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004017 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004018
Florian Grandel7816b822015-06-18 03:16:45 +02004019 cancel_adv_timeout(hdev);
4020
Arman Uguray24b4f382015-03-23 15:57:12 -07004021 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004022 /* Switch to instance "0" for the Set Advertising setting.
4023 * We cannot use update_[adv|scan_rsp]_data() here as the
4024 * HCI_ADVERTISING flag is not yet set.
4025 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004026 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02004027 __hci_req_update_adv_data(&req, 0x00);
4028 __hci_req_update_scan_rsp_data(&req, 0x00);
4029 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004030 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004031 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004032 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004033
4034 err = hci_req_run(&req, set_advertising_complete);
4035 if (err < 0)
4036 mgmt_pending_remove(cmd);
4037
4038unlock:
4039 hci_dev_unlock(hdev);
4040 return err;
4041}
4042
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004043static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4044 void *data, u16 len)
4045{
4046 struct mgmt_cp_set_static_address *cp = data;
4047 int err;
4048
4049 BT_DBG("%s", hdev->name);
4050
Marcel Holtmann62af4442013-10-02 22:10:32 -07004051 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004052 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4053 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004054
4055 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004056 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4057 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004058
4059 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4060 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004061 return mgmt_cmd_status(sk, hdev->id,
4062 MGMT_OP_SET_STATIC_ADDRESS,
4063 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004064
4065 /* Two most significant bits shall be set */
4066 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004067 return mgmt_cmd_status(sk, hdev->id,
4068 MGMT_OP_SET_STATIC_ADDRESS,
4069 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004070 }
4071
4072 hci_dev_lock(hdev);
4073
4074 bacpy(&hdev->static_addr, &cp->bdaddr);
4075
Marcel Holtmann93690c22015-03-06 10:11:21 -08004076 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4077 if (err < 0)
4078 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004079
Marcel Holtmann93690c22015-03-06 10:11:21 -08004080 err = new_settings(hdev, sk);
4081
4082unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004083 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004084 return err;
4085}
4086
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004087static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4088 void *data, u16 len)
4089{
4090 struct mgmt_cp_set_scan_params *cp = data;
4091 __u16 interval, window;
4092 int err;
4093
4094 BT_DBG("%s", hdev->name);
4095
4096 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004097 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4098 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004099
4100 interval = __le16_to_cpu(cp->interval);
4101
4102 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004103 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4104 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004105
4106 window = __le16_to_cpu(cp->window);
4107
4108 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004109 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4110 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004111
Marcel Holtmann899e1072013-10-14 09:55:32 -07004112 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004113 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4114 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004115
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004116 hci_dev_lock(hdev);
4117
4118 hdev->le_scan_interval = interval;
4119 hdev->le_scan_window = window;
4120
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004121 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4122 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004123
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004124 /* If background scan is running, restart it so new parameters are
4125 * loaded.
4126 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004127 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004128 hdev->discovery.state == DISCOVERY_STOPPED) {
4129 struct hci_request req;
4130
4131 hci_req_init(&req, hdev);
4132
4133 hci_req_add_le_scan_disable(&req);
4134 hci_req_add_le_passive_scan(&req);
4135
4136 hci_req_run(&req, NULL);
4137 }
4138
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004139 hci_dev_unlock(hdev);
4140
4141 return err;
4142}
4143
Marcel Holtmann1904a852015-01-11 13:50:44 -08004144static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4145 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004146{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004147 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004148
4149 BT_DBG("status 0x%02x", status);
4150
4151 hci_dev_lock(hdev);
4152
Johan Hedberg333ae952015-03-17 13:48:47 +02004153 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004154 if (!cmd)
4155 goto unlock;
4156
4157 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004158 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4159 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004160 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004161 struct mgmt_mode *cp = cmd->param;
4162
4163 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004164 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004165 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004166 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004167
Johan Hedberg33e38b32013-03-15 17:07:05 -05004168 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4169 new_settings(hdev, cmd->sk);
4170 }
4171
4172 mgmt_pending_remove(cmd);
4173
4174unlock:
4175 hci_dev_unlock(hdev);
4176}
4177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004178static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004179 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004180{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004181 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004182 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004183 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004184 int err;
4185
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004186 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004187
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004188 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004189 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004190 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4191 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004192
Johan Hedberga7e80f22013-01-09 16:05:19 +02004193 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004194 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4195 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004196
Antti Julkuf6422ec2011-06-22 13:11:56 +03004197 hci_dev_lock(hdev);
4198
Johan Hedberg333ae952015-03-17 13:48:47 +02004199 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004200 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4201 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004202 goto unlock;
4203 }
4204
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004205 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004206 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4207 hdev);
4208 goto unlock;
4209 }
4210
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004211 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004212 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004213 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4214 hdev);
4215 new_settings(hdev, sk);
4216 goto unlock;
4217 }
4218
Johan Hedberg33e38b32013-03-15 17:07:05 -05004219 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4220 data, len);
4221 if (!cmd) {
4222 err = -ENOMEM;
4223 goto unlock;
4224 }
4225
4226 hci_req_init(&req, hdev);
4227
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004228 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004229
4230 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004231 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4233 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004234 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004235 }
4236
Johan Hedberg33e38b32013-03-15 17:07:05 -05004237unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004238 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004239
Antti Julkuf6422ec2011-06-22 13:11:56 +03004240 return err;
4241}
4242
Marcel Holtmann1904a852015-01-11 13:50:44 -08004243static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004244{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004245 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004246
4247 BT_DBG("status 0x%02x", status);
4248
4249 hci_dev_lock(hdev);
4250
Johan Hedberg333ae952015-03-17 13:48:47 +02004251 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004252 if (!cmd)
4253 goto unlock;
4254
4255 if (status) {
4256 u8 mgmt_err = mgmt_status(status);
4257
4258 /* We need to restore the flag if related HCI commands
4259 * failed.
4260 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004261 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004262
Johan Hedberga69e8372015-03-06 21:08:53 +02004263 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004264 } else {
4265 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4266 new_settings(hdev, cmd->sk);
4267 }
4268
4269 mgmt_pending_remove(cmd);
4270
4271unlock:
4272 hci_dev_unlock(hdev);
4273}
4274
4275static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4276{
4277 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004278 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004279 struct hci_request req;
4280 int err;
4281
4282 BT_DBG("request for %s", hdev->name);
4283
4284 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004285 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4286 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004287
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004288 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004289 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4290 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004291
4292 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4294 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004295
4296 hci_dev_lock(hdev);
4297
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004298 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004299 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4300 goto unlock;
4301 }
4302
4303 if (!hdev_is_powered(hdev)) {
4304 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004305 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4306 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4307 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4308 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4309 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004310 }
4311
Marcel Holtmannce05d602015-03-13 02:11:03 -07004312 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004313
4314 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4315 if (err < 0)
4316 goto unlock;
4317
4318 err = new_settings(hdev, sk);
4319 goto unlock;
4320 }
4321
4322 /* Reject disabling when powered on */
4323 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004324 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4325 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004326 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004327 } else {
4328 /* When configuring a dual-mode controller to operate
4329 * with LE only and using a static address, then switching
4330 * BR/EDR back on is not allowed.
4331 *
4332 * Dual-mode controllers shall operate with the public
4333 * address as its identity address for BR/EDR and LE. So
4334 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004335 *
4336 * The same restrictions applies when secure connections
4337 * has been enabled. For BR/EDR this is a controller feature
4338 * while for LE it is a host stack feature. This means that
4339 * switching BR/EDR back on when secure connections has been
4340 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004341 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004342 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004343 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004344 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004345 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4346 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004347 goto unlock;
4348 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004349 }
4350
Johan Hedberg333ae952015-03-17 13:48:47 +02004351 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004352 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4353 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004354 goto unlock;
4355 }
4356
4357 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4358 if (!cmd) {
4359 err = -ENOMEM;
4360 goto unlock;
4361 }
4362
Johan Hedbergf2252572015-11-18 12:49:20 +02004363 /* We need to flip the bit already here so that
4364 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004365 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004366 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004367
4368 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004369
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004370 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004371 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004372
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004373 /* Since only the advertising data flags will change, there
4374 * is no need to update the scan response data.
4375 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004376 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004377
Johan Hedberg0663ca22013-10-02 13:43:14 +03004378 err = hci_req_run(&req, set_bredr_complete);
4379 if (err < 0)
4380 mgmt_pending_remove(cmd);
4381
4382unlock:
4383 hci_dev_unlock(hdev);
4384 return err;
4385}
4386
Johan Hedberga1443f52015-01-23 15:42:46 +02004387static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4388{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004389 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004390 struct mgmt_mode *cp;
4391
4392 BT_DBG("%s status %u", hdev->name, status);
4393
4394 hci_dev_lock(hdev);
4395
Johan Hedberg333ae952015-03-17 13:48:47 +02004396 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004397 if (!cmd)
4398 goto unlock;
4399
4400 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004401 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4402 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004403 goto remove;
4404 }
4405
4406 cp = cmd->param;
4407
4408 switch (cp->val) {
4409 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004410 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4411 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004412 break;
4413 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004414 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004415 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004416 break;
4417 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004418 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4419 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004420 break;
4421 }
4422
4423 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4424 new_settings(hdev, cmd->sk);
4425
4426remove:
4427 mgmt_pending_remove(cmd);
4428unlock:
4429 hci_dev_unlock(hdev);
4430}
4431
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004432static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4433 void *data, u16 len)
4434{
4435 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004436 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004437 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004438 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004439 int err;
4440
4441 BT_DBG("request for %s", hdev->name);
4442
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004443 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004444 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004445 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4446 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004447
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004448 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004449 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004450 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004451 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4452 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004453
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004454 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004455 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004456 MGMT_STATUS_INVALID_PARAMS);
4457
4458 hci_dev_lock(hdev);
4459
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004460 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004461 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004462 bool changed;
4463
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004464 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004465 changed = !hci_dev_test_and_set_flag(hdev,
4466 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004467 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004468 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004469 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004470 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004471 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004472 changed = hci_dev_test_and_clear_flag(hdev,
4473 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004474 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004475 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004476
4477 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4478 if (err < 0)
4479 goto failed;
4480
4481 if (changed)
4482 err = new_settings(hdev, sk);
4483
4484 goto failed;
4485 }
4486
Johan Hedberg333ae952015-03-17 13:48:47 +02004487 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004488 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4489 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004490 goto failed;
4491 }
4492
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004493 val = !!cp->val;
4494
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004495 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4496 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004497 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4498 goto failed;
4499 }
4500
4501 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4502 if (!cmd) {
4503 err = -ENOMEM;
4504 goto failed;
4505 }
4506
Johan Hedberga1443f52015-01-23 15:42:46 +02004507 hci_req_init(&req, hdev);
4508 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4509 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004510 if (err < 0) {
4511 mgmt_pending_remove(cmd);
4512 goto failed;
4513 }
4514
4515failed:
4516 hci_dev_unlock(hdev);
4517 return err;
4518}
4519
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004520static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4521 void *data, u16 len)
4522{
4523 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004524 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004525 int err;
4526
4527 BT_DBG("request for %s", hdev->name);
4528
Johan Hedbergb97109792014-06-24 14:00:28 +03004529 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004530 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4531 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004532
4533 hci_dev_lock(hdev);
4534
4535 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004536 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004537 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004538 changed = hci_dev_test_and_clear_flag(hdev,
4539 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004540
Johan Hedbergb97109792014-06-24 14:00:28 +03004541 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004542 use_changed = !hci_dev_test_and_set_flag(hdev,
4543 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004544 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004545 use_changed = hci_dev_test_and_clear_flag(hdev,
4546 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004547
4548 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004549 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004550 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4551 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4552 sizeof(mode), &mode);
4553 }
4554
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004555 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4556 if (err < 0)
4557 goto unlock;
4558
4559 if (changed)
4560 err = new_settings(hdev, sk);
4561
4562unlock:
4563 hci_dev_unlock(hdev);
4564 return err;
4565}
4566
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004567static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4568 u16 len)
4569{
4570 struct mgmt_cp_set_privacy *cp = cp_data;
4571 bool changed;
4572 int err;
4573
4574 BT_DBG("request for %s", hdev->name);
4575
4576 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004577 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4578 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004579
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004580 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004581 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4582 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004583
4584 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004585 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4586 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004587
4588 hci_dev_lock(hdev);
4589
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004590 /* If user space supports this command it is also expected to
4591 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4592 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004593 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004594
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004595 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004596 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004597 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004598 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004599 if (cp->privacy == 0x02)
4600 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4601 else
4602 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004603 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004604 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004605 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004606 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004607 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004608 }
4609
4610 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4611 if (err < 0)
4612 goto unlock;
4613
4614 if (changed)
4615 err = new_settings(hdev, sk);
4616
4617unlock:
4618 hci_dev_unlock(hdev);
4619 return err;
4620}
4621
Johan Hedberg41edf162014-02-18 10:19:35 +02004622static bool irk_is_valid(struct mgmt_irk_info *irk)
4623{
4624 switch (irk->addr.type) {
4625 case BDADDR_LE_PUBLIC:
4626 return true;
4627
4628 case BDADDR_LE_RANDOM:
4629 /* Two most significant bits shall be set */
4630 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4631 return false;
4632 return true;
4633 }
4634
4635 return false;
4636}
4637
4638static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4639 u16 len)
4640{
4641 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004642 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4643 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004644 u16 irk_count, expected_len;
4645 int i, err;
4646
4647 BT_DBG("request for %s", hdev->name);
4648
4649 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004650 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4651 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004652
4653 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004654 if (irk_count > max_irk_count) {
4655 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004656 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4657 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004658 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004659
4660 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4661 if (expected_len != len) {
4662 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004663 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004664 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4665 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004666 }
4667
4668 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4669
4670 for (i = 0; i < irk_count; i++) {
4671 struct mgmt_irk_info *key = &cp->irks[i];
4672
4673 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004674 return mgmt_cmd_status(sk, hdev->id,
4675 MGMT_OP_LOAD_IRKS,
4676 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004677 }
4678
4679 hci_dev_lock(hdev);
4680
4681 hci_smp_irks_clear(hdev);
4682
4683 for (i = 0; i < irk_count; i++) {
4684 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004685
Johan Hedberg85813a72015-10-21 18:02:59 +03004686 hci_add_irk(hdev, &irk->addr.bdaddr,
4687 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004688 BDADDR_ANY);
4689 }
4690
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004691 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004692
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004693 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004694
4695 hci_dev_unlock(hdev);
4696
4697 return err;
4698}
4699
Johan Hedberg3f706b72013-01-20 14:27:16 +02004700static bool ltk_is_valid(struct mgmt_ltk_info *key)
4701{
4702 if (key->master != 0x00 && key->master != 0x01)
4703 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004704
4705 switch (key->addr.type) {
4706 case BDADDR_LE_PUBLIC:
4707 return true;
4708
4709 case BDADDR_LE_RANDOM:
4710 /* Two most significant bits shall be set */
4711 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4712 return false;
4713 return true;
4714 }
4715
4716 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004717}
4718
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004719static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004720 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004721{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004722 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004723 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4724 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004725 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004726 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004727
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004728 BT_DBG("request for %s", hdev->name);
4729
4730 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004731 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4732 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004733
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004734 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004735 if (key_count > max_key_count) {
4736 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004737 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4738 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004739 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004740
4741 expected_len = sizeof(*cp) + key_count *
4742 sizeof(struct mgmt_ltk_info);
4743 if (expected_len != len) {
4744 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004745 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004746 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4747 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004748 }
4749
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004750 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004751
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004752 for (i = 0; i < key_count; i++) {
4753 struct mgmt_ltk_info *key = &cp->keys[i];
4754
Johan Hedberg3f706b72013-01-20 14:27:16 +02004755 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004756 return mgmt_cmd_status(sk, hdev->id,
4757 MGMT_OP_LOAD_LONG_TERM_KEYS,
4758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004759 }
4760
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004761 hci_dev_lock(hdev);
4762
4763 hci_smp_ltks_clear(hdev);
4764
4765 for (i = 0; i < key_count; i++) {
4766 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004767 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004768
Johan Hedberg61b43352014-05-29 19:36:53 +03004769 switch (key->type) {
4770 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004771 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004772 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004773 break;
4774 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004775 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004776 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004777 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004778 case MGMT_LTK_P256_UNAUTH:
4779 authenticated = 0x00;
4780 type = SMP_LTK_P256;
4781 break;
4782 case MGMT_LTK_P256_AUTH:
4783 authenticated = 0x01;
4784 type = SMP_LTK_P256;
4785 break;
4786 case MGMT_LTK_P256_DEBUG:
4787 authenticated = 0x00;
4788 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004789 default:
4790 continue;
4791 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004792
Johan Hedberg85813a72015-10-21 18:02:59 +03004793 hci_add_ltk(hdev, &key->addr.bdaddr,
4794 le_addr_type(key->addr.type), type, authenticated,
4795 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004796 }
4797
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004798 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004799 NULL, 0);
4800
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004801 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004802
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004803 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004804}
4805
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004806static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004807{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004808 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004809 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004810 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004811
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004812 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004813
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004814 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004815 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004816 rp.tx_power = conn->tx_power;
4817 rp.max_tx_power = conn->max_tx_power;
4818 } else {
4819 rp.rssi = HCI_RSSI_INVALID;
4820 rp.tx_power = HCI_TX_POWER_INVALID;
4821 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004822 }
4823
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004824 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4825 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004826
4827 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004828 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004829
4830 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004831}
4832
Marcel Holtmann1904a852015-01-11 13:50:44 -08004833static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4834 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004835{
4836 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004837 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004838 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004839 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004840 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004841
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004842 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004843
4844 hci_dev_lock(hdev);
4845
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004846 /* Commands sent in request are either Read RSSI or Read Transmit Power
4847 * Level so we check which one was last sent to retrieve connection
4848 * handle. Both commands have handle as first parameter so it's safe to
4849 * cast data on the same command struct.
4850 *
4851 * First command sent is always Read RSSI and we fail only if it fails.
4852 * In other case we simply override error to indicate success as we
4853 * already remembered if TX power value is actually valid.
4854 */
4855 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4856 if (!cp) {
4857 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004858 status = MGMT_STATUS_SUCCESS;
4859 } else {
4860 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004861 }
4862
4863 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004864 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004865 goto unlock;
4866 }
4867
4868 handle = __le16_to_cpu(cp->handle);
4869 conn = hci_conn_hash_lookup_handle(hdev, handle);
4870 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004871 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004872 goto unlock;
4873 }
4874
Johan Hedberg333ae952015-03-17 13:48:47 +02004875 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004876 if (!cmd)
4877 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004878
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004879 cmd->cmd_complete(cmd, status);
4880 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004881
4882unlock:
4883 hci_dev_unlock(hdev);
4884}
4885
4886static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4887 u16 len)
4888{
4889 struct mgmt_cp_get_conn_info *cp = data;
4890 struct mgmt_rp_get_conn_info rp;
4891 struct hci_conn *conn;
4892 unsigned long conn_info_age;
4893 int err = 0;
4894
4895 BT_DBG("%s", hdev->name);
4896
4897 memset(&rp, 0, sizeof(rp));
4898 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4899 rp.addr.type = cp->addr.type;
4900
4901 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004902 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4903 MGMT_STATUS_INVALID_PARAMS,
4904 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004905
4906 hci_dev_lock(hdev);
4907
4908 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004909 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4910 MGMT_STATUS_NOT_POWERED, &rp,
4911 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004912 goto unlock;
4913 }
4914
4915 if (cp->addr.type == BDADDR_BREDR)
4916 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4917 &cp->addr.bdaddr);
4918 else
4919 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4920
4921 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004922 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4923 MGMT_STATUS_NOT_CONNECTED, &rp,
4924 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004925 goto unlock;
4926 }
4927
Johan Hedberg333ae952015-03-17 13:48:47 +02004928 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004929 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4930 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004931 goto unlock;
4932 }
4933
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004934 /* To avoid client trying to guess when to poll again for information we
4935 * calculate conn info age as random value between min/max set in hdev.
4936 */
4937 conn_info_age = hdev->conn_info_min_age +
4938 prandom_u32_max(hdev->conn_info_max_age -
4939 hdev->conn_info_min_age);
4940
4941 /* Query controller to refresh cached values if they are too old or were
4942 * never read.
4943 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004944 if (time_after(jiffies, conn->conn_info_timestamp +
4945 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004946 !conn->conn_info_timestamp) {
4947 struct hci_request req;
4948 struct hci_cp_read_tx_power req_txp_cp;
4949 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004950 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004951
4952 hci_req_init(&req, hdev);
4953 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4954 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4955 &req_rssi_cp);
4956
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004957 /* For LE links TX power does not change thus we don't need to
4958 * query for it once value is known.
4959 */
4960 if (!bdaddr_type_is_le(cp->addr.type) ||
4961 conn->tx_power == HCI_TX_POWER_INVALID) {
4962 req_txp_cp.handle = cpu_to_le16(conn->handle);
4963 req_txp_cp.type = 0x00;
4964 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4965 sizeof(req_txp_cp), &req_txp_cp);
4966 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004967
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004968 /* Max TX power needs to be read only once per connection */
4969 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4970 req_txp_cp.handle = cpu_to_le16(conn->handle);
4971 req_txp_cp.type = 0x01;
4972 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4973 sizeof(req_txp_cp), &req_txp_cp);
4974 }
4975
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004976 err = hci_req_run(&req, conn_info_refresh_complete);
4977 if (err < 0)
4978 goto unlock;
4979
4980 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4981 data, len);
4982 if (!cmd) {
4983 err = -ENOMEM;
4984 goto unlock;
4985 }
4986
4987 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004988 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004989 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004990
4991 conn->conn_info_timestamp = jiffies;
4992 } else {
4993 /* Cache is valid, just reply with values cached in hci_conn */
4994 rp.rssi = conn->rssi;
4995 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004996 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004997
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004998 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4999 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005000 }
5001
5002unlock:
5003 hci_dev_unlock(hdev);
5004 return err;
5005}
5006
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005007static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005008{
5009 struct hci_conn *conn = cmd->user_data;
5010 struct mgmt_rp_get_clock_info rp;
5011 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005012 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005013
5014 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02005015 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02005016
5017 if (status)
5018 goto complete;
5019
5020 hdev = hci_dev_get(cmd->index);
5021 if (hdev) {
5022 rp.local_clock = cpu_to_le32(hdev->clock);
5023 hci_dev_put(hdev);
5024 }
5025
5026 if (conn) {
5027 rp.piconet_clock = cpu_to_le32(conn->clock);
5028 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5029 }
5030
5031complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005032 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5033 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005034
5035 if (conn) {
5036 hci_conn_drop(conn);
5037 hci_conn_put(conn);
5038 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005039
5040 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005041}
5042
Marcel Holtmann1904a852015-01-11 13:50:44 -08005043static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005044{
Johan Hedberg95868422014-06-28 17:54:07 +03005045 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005046 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005047 struct hci_conn *conn;
5048
5049 BT_DBG("%s status %u", hdev->name, status);
5050
5051 hci_dev_lock(hdev);
5052
5053 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5054 if (!hci_cp)
5055 goto unlock;
5056
5057 if (hci_cp->which) {
5058 u16 handle = __le16_to_cpu(hci_cp->handle);
5059 conn = hci_conn_hash_lookup_handle(hdev, handle);
5060 } else {
5061 conn = NULL;
5062 }
5063
Johan Hedberg333ae952015-03-17 13:48:47 +02005064 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005065 if (!cmd)
5066 goto unlock;
5067
Johan Hedberg69487372014-12-05 13:36:07 +02005068 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005069 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005070
5071unlock:
5072 hci_dev_unlock(hdev);
5073}
5074
5075static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5076 u16 len)
5077{
5078 struct mgmt_cp_get_clock_info *cp = data;
5079 struct mgmt_rp_get_clock_info rp;
5080 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005081 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005082 struct hci_request req;
5083 struct hci_conn *conn;
5084 int err;
5085
5086 BT_DBG("%s", hdev->name);
5087
5088 memset(&rp, 0, sizeof(rp));
5089 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5090 rp.addr.type = cp->addr.type;
5091
5092 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005093 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5094 MGMT_STATUS_INVALID_PARAMS,
5095 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005096
5097 hci_dev_lock(hdev);
5098
5099 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005100 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5101 MGMT_STATUS_NOT_POWERED, &rp,
5102 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005103 goto unlock;
5104 }
5105
5106 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5107 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5108 &cp->addr.bdaddr);
5109 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005110 err = mgmt_cmd_complete(sk, hdev->id,
5111 MGMT_OP_GET_CLOCK_INFO,
5112 MGMT_STATUS_NOT_CONNECTED,
5113 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005114 goto unlock;
5115 }
5116 } else {
5117 conn = NULL;
5118 }
5119
5120 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5121 if (!cmd) {
5122 err = -ENOMEM;
5123 goto unlock;
5124 }
5125
Johan Hedberg69487372014-12-05 13:36:07 +02005126 cmd->cmd_complete = clock_info_cmd_complete;
5127
Johan Hedberg95868422014-06-28 17:54:07 +03005128 hci_req_init(&req, hdev);
5129
5130 memset(&hci_cp, 0, sizeof(hci_cp));
5131 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5132
5133 if (conn) {
5134 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005135 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005136
5137 hci_cp.handle = cpu_to_le16(conn->handle);
5138 hci_cp.which = 0x01; /* Piconet clock */
5139 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5140 }
5141
5142 err = hci_req_run(&req, get_clock_info_complete);
5143 if (err < 0)
5144 mgmt_pending_remove(cmd);
5145
5146unlock:
5147 hci_dev_unlock(hdev);
5148 return err;
5149}
5150
Johan Hedberg5a154e62014-12-19 22:26:02 +02005151static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5152{
5153 struct hci_conn *conn;
5154
5155 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5156 if (!conn)
5157 return false;
5158
5159 if (conn->dst_type != type)
5160 return false;
5161
5162 if (conn->state != BT_CONNECTED)
5163 return false;
5164
5165 return true;
5166}
5167
5168/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005169static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005170 u8 addr_type, u8 auto_connect)
5171{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005172 struct hci_conn_params *params;
5173
5174 params = hci_conn_params_add(hdev, addr, addr_type);
5175 if (!params)
5176 return -EIO;
5177
5178 if (params->auto_connect == auto_connect)
5179 return 0;
5180
5181 list_del_init(&params->action);
5182
5183 switch (auto_connect) {
5184 case HCI_AUTO_CONN_DISABLED:
5185 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005186 /* If auto connect is being disabled when we're trying to
5187 * connect to device, keep connecting.
5188 */
5189 if (params->explicit_connect)
5190 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005191 break;
5192 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005193 if (params->explicit_connect)
5194 list_add(&params->action, &hdev->pend_le_conns);
5195 else
5196 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005197 break;
5198 case HCI_AUTO_CONN_DIRECT:
5199 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005200 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005201 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005202 break;
5203 }
5204
5205 params->auto_connect = auto_connect;
5206
5207 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5208 auto_connect);
5209
5210 return 0;
5211}
5212
Marcel Holtmann8afef092014-06-29 22:28:34 +02005213static void device_added(struct sock *sk, struct hci_dev *hdev,
5214 bdaddr_t *bdaddr, u8 type, u8 action)
5215{
5216 struct mgmt_ev_device_added ev;
5217
5218 bacpy(&ev.addr.bdaddr, bdaddr);
5219 ev.addr.type = type;
5220 ev.action = action;
5221
5222 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5223}
5224
Marcel Holtmann2faade52014-06-29 19:44:03 +02005225static int add_device(struct sock *sk, struct hci_dev *hdev,
5226 void *data, u16 len)
5227{
5228 struct mgmt_cp_add_device *cp = data;
5229 u8 auto_conn, addr_type;
5230 int err;
5231
5232 BT_DBG("%s", hdev->name);
5233
Johan Hedberg66593582014-07-09 12:59:14 +03005234 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005235 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005236 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5237 MGMT_STATUS_INVALID_PARAMS,
5238 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005239
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005240 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005241 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5242 MGMT_STATUS_INVALID_PARAMS,
5243 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005244
5245 hci_dev_lock(hdev);
5246
Johan Hedberg66593582014-07-09 12:59:14 +03005247 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005248 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005249 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005250 err = mgmt_cmd_complete(sk, hdev->id,
5251 MGMT_OP_ADD_DEVICE,
5252 MGMT_STATUS_INVALID_PARAMS,
5253 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005254 goto unlock;
5255 }
5256
5257 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5258 cp->addr.type);
5259 if (err)
5260 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005261
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005262 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005263
Johan Hedberg66593582014-07-09 12:59:14 +03005264 goto added;
5265 }
5266
Johan Hedberg85813a72015-10-21 18:02:59 +03005267 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005268
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005269 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005270 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005271 else if (cp->action == 0x01)
5272 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005273 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005274 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005275
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005276 /* Kernel internally uses conn_params with resolvable private
5277 * address, but Add Device allows only identity addresses.
5278 * Make sure it is enforced before calling
5279 * hci_conn_params_lookup.
5280 */
5281 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005282 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5283 MGMT_STATUS_INVALID_PARAMS,
5284 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005285 goto unlock;
5286 }
5287
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005288 /* If the connection parameters don't exist for this device,
5289 * they will be created and configured with defaults.
5290 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005291 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005292 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005293 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5294 MGMT_STATUS_FAILED, &cp->addr,
5295 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005296 goto unlock;
5297 }
5298
Johan Hedberg51d7a942015-11-11 08:11:18 +02005299 hci_update_background_scan(hdev);
5300
Johan Hedberg66593582014-07-09 12:59:14 +03005301added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005302 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5303
Johan Hedberg51d7a942015-11-11 08:11:18 +02005304 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5305 MGMT_STATUS_SUCCESS, &cp->addr,
5306 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005307
5308unlock:
5309 hci_dev_unlock(hdev);
5310 return err;
5311}
5312
Marcel Holtmann8afef092014-06-29 22:28:34 +02005313static void device_removed(struct sock *sk, struct hci_dev *hdev,
5314 bdaddr_t *bdaddr, u8 type)
5315{
5316 struct mgmt_ev_device_removed ev;
5317
5318 bacpy(&ev.addr.bdaddr, bdaddr);
5319 ev.addr.type = type;
5320
5321 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5322}
5323
Marcel Holtmann2faade52014-06-29 19:44:03 +02005324static int remove_device(struct sock *sk, struct hci_dev *hdev,
5325 void *data, u16 len)
5326{
5327 struct mgmt_cp_remove_device *cp = data;
5328 int err;
5329
5330 BT_DBG("%s", hdev->name);
5331
5332 hci_dev_lock(hdev);
5333
5334 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005335 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005336 u8 addr_type;
5337
Johan Hedberg66593582014-07-09 12:59:14 +03005338 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005339 err = mgmt_cmd_complete(sk, hdev->id,
5340 MGMT_OP_REMOVE_DEVICE,
5341 MGMT_STATUS_INVALID_PARAMS,
5342 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005343 goto unlock;
5344 }
5345
Johan Hedberg66593582014-07-09 12:59:14 +03005346 if (cp->addr.type == BDADDR_BREDR) {
5347 err = hci_bdaddr_list_del(&hdev->whitelist,
5348 &cp->addr.bdaddr,
5349 cp->addr.type);
5350 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005351 err = mgmt_cmd_complete(sk, hdev->id,
5352 MGMT_OP_REMOVE_DEVICE,
5353 MGMT_STATUS_INVALID_PARAMS,
5354 &cp->addr,
5355 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005356 goto unlock;
5357 }
5358
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005359 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005360
Johan Hedberg66593582014-07-09 12:59:14 +03005361 device_removed(sk, hdev, &cp->addr.bdaddr,
5362 cp->addr.type);
5363 goto complete;
5364 }
5365
Johan Hedberg85813a72015-10-21 18:02:59 +03005366 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005367
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005368 /* Kernel internally uses conn_params with resolvable private
5369 * address, but Remove Device allows only identity addresses.
5370 * Make sure it is enforced before calling
5371 * hci_conn_params_lookup.
5372 */
5373 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005374 err = mgmt_cmd_complete(sk, hdev->id,
5375 MGMT_OP_REMOVE_DEVICE,
5376 MGMT_STATUS_INVALID_PARAMS,
5377 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005378 goto unlock;
5379 }
5380
Johan Hedbergc71593d2014-07-02 17:37:28 +03005381 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5382 addr_type);
5383 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005384 err = mgmt_cmd_complete(sk, hdev->id,
5385 MGMT_OP_REMOVE_DEVICE,
5386 MGMT_STATUS_INVALID_PARAMS,
5387 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005388 goto unlock;
5389 }
5390
Johan Hedberg679d2b62015-10-16 10:07:52 +03005391 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5392 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
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));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005397 goto unlock;
5398 }
5399
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005400 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005401 list_del(&params->list);
5402 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005403 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005404
5405 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005406 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005407 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005408 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005409
Marcel Holtmann2faade52014-06-29 19:44:03 +02005410 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005411 err = mgmt_cmd_complete(sk, hdev->id,
5412 MGMT_OP_REMOVE_DEVICE,
5413 MGMT_STATUS_INVALID_PARAMS,
5414 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005415 goto unlock;
5416 }
5417
Johan Hedberg66593582014-07-09 12:59:14 +03005418 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5419 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5420 list_del(&b->list);
5421 kfree(b);
5422 }
5423
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005424 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005425
Johan Hedberg19de0822014-07-06 13:06:51 +03005426 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5427 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5428 continue;
5429 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005430 if (p->explicit_connect) {
5431 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5432 continue;
5433 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005434 list_del(&p->action);
5435 list_del(&p->list);
5436 kfree(p);
5437 }
5438
5439 BT_DBG("All LE connection parameters were removed");
5440
Johan Hedberg51d7a942015-11-11 08:11:18 +02005441 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005442 }
5443
Johan Hedberg66593582014-07-09 12:59:14 +03005444complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005445 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5446 MGMT_STATUS_SUCCESS, &cp->addr,
5447 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005448unlock:
5449 hci_dev_unlock(hdev);
5450 return err;
5451}
5452
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005453static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5454 u16 len)
5455{
5456 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005457 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5458 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005459 u16 param_count, expected_len;
5460 int i;
5461
5462 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005463 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5464 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005465
5466 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005467 if (param_count > max_param_count) {
5468 BT_ERR("load_conn_param: too big param_count value %u",
5469 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005470 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5471 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005472 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005473
5474 expected_len = sizeof(*cp) + param_count *
5475 sizeof(struct mgmt_conn_param);
5476 if (expected_len != len) {
5477 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5478 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005479 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5480 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005481 }
5482
5483 BT_DBG("%s param_count %u", hdev->name, param_count);
5484
5485 hci_dev_lock(hdev);
5486
5487 hci_conn_params_clear_disabled(hdev);
5488
5489 for (i = 0; i < param_count; i++) {
5490 struct mgmt_conn_param *param = &cp->params[i];
5491 struct hci_conn_params *hci_param;
5492 u16 min, max, latency, timeout;
5493 u8 addr_type;
5494
5495 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5496 param->addr.type);
5497
5498 if (param->addr.type == BDADDR_LE_PUBLIC) {
5499 addr_type = ADDR_LE_DEV_PUBLIC;
5500 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5501 addr_type = ADDR_LE_DEV_RANDOM;
5502 } else {
5503 BT_ERR("Ignoring invalid connection parameters");
5504 continue;
5505 }
5506
5507 min = le16_to_cpu(param->min_interval);
5508 max = le16_to_cpu(param->max_interval);
5509 latency = le16_to_cpu(param->latency);
5510 timeout = le16_to_cpu(param->timeout);
5511
5512 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5513 min, max, latency, timeout);
5514
5515 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5516 BT_ERR("Ignoring invalid connection parameters");
5517 continue;
5518 }
5519
5520 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5521 addr_type);
5522 if (!hci_param) {
5523 BT_ERR("Failed to add connection parameters");
5524 continue;
5525 }
5526
5527 hci_param->conn_min_interval = min;
5528 hci_param->conn_max_interval = max;
5529 hci_param->conn_latency = latency;
5530 hci_param->supervision_timeout = timeout;
5531 }
5532
5533 hci_dev_unlock(hdev);
5534
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005535 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5536 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005537}
5538
Marcel Holtmanndbece372014-07-04 18:11:55 +02005539static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5540 void *data, u16 len)
5541{
5542 struct mgmt_cp_set_external_config *cp = data;
5543 bool changed;
5544 int err;
5545
5546 BT_DBG("%s", hdev->name);
5547
5548 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005549 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5550 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005551
5552 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005553 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5554 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005555
5556 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005557 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5558 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005559
5560 hci_dev_lock(hdev);
5561
5562 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005563 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005564 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005565 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005566
5567 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5568 if (err < 0)
5569 goto unlock;
5570
5571 if (!changed)
5572 goto unlock;
5573
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005574 err = new_options(hdev, sk);
5575
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005576 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005577 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005578
Marcel Holtmann516018a2015-03-13 02:11:04 -07005579 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005580 hci_dev_set_flag(hdev, HCI_CONFIG);
5581 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005582
5583 queue_work(hdev->req_workqueue, &hdev->power_on);
5584 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005585 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005586 mgmt_index_added(hdev);
5587 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005588 }
5589
5590unlock:
5591 hci_dev_unlock(hdev);
5592 return err;
5593}
5594
Marcel Holtmann9713c172014-07-06 12:11:15 +02005595static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5596 void *data, u16 len)
5597{
5598 struct mgmt_cp_set_public_address *cp = data;
5599 bool changed;
5600 int err;
5601
5602 BT_DBG("%s", hdev->name);
5603
5604 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005605 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5606 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005607
5608 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005609 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5610 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005611
5612 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005613 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5614 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005615
5616 hci_dev_lock(hdev);
5617
5618 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5619 bacpy(&hdev->public_addr, &cp->bdaddr);
5620
5621 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5622 if (err < 0)
5623 goto unlock;
5624
5625 if (!changed)
5626 goto unlock;
5627
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005628 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005629 err = new_options(hdev, sk);
5630
5631 if (is_configured(hdev)) {
5632 mgmt_index_removed(hdev);
5633
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005634 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005635
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005636 hci_dev_set_flag(hdev, HCI_CONFIG);
5637 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005638
5639 queue_work(hdev->req_workqueue, &hdev->power_on);
5640 }
5641
5642unlock:
5643 hci_dev_unlock(hdev);
5644 return err;
5645}
5646
Johan Hedberg40f66c02015-04-07 21:52:22 +03005647static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5648 u16 opcode, struct sk_buff *skb)
5649{
5650 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5651 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5652 u8 *h192, *r192, *h256, *r256;
5653 struct mgmt_pending_cmd *cmd;
5654 u16 eir_len;
5655 int err;
5656
5657 BT_DBG("%s status %u", hdev->name, status);
5658
5659 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5660 if (!cmd)
5661 return;
5662
5663 mgmt_cp = cmd->param;
5664
5665 if (status) {
5666 status = mgmt_status(status);
5667 eir_len = 0;
5668
5669 h192 = NULL;
5670 r192 = NULL;
5671 h256 = NULL;
5672 r256 = NULL;
5673 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5674 struct hci_rp_read_local_oob_data *rp;
5675
5676 if (skb->len != sizeof(*rp)) {
5677 status = MGMT_STATUS_FAILED;
5678 eir_len = 0;
5679 } else {
5680 status = MGMT_STATUS_SUCCESS;
5681 rp = (void *)skb->data;
5682
5683 eir_len = 5 + 18 + 18;
5684 h192 = rp->hash;
5685 r192 = rp->rand;
5686 h256 = NULL;
5687 r256 = NULL;
5688 }
5689 } else {
5690 struct hci_rp_read_local_oob_ext_data *rp;
5691
5692 if (skb->len != sizeof(*rp)) {
5693 status = MGMT_STATUS_FAILED;
5694 eir_len = 0;
5695 } else {
5696 status = MGMT_STATUS_SUCCESS;
5697 rp = (void *)skb->data;
5698
5699 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5700 eir_len = 5 + 18 + 18;
5701 h192 = NULL;
5702 r192 = NULL;
5703 } else {
5704 eir_len = 5 + 18 + 18 + 18 + 18;
5705 h192 = rp->hash192;
5706 r192 = rp->rand192;
5707 }
5708
5709 h256 = rp->hash256;
5710 r256 = rp->rand256;
5711 }
5712 }
5713
5714 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5715 if (!mgmt_rp)
5716 goto done;
5717
5718 if (status)
5719 goto send_rsp;
5720
5721 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5722 hdev->dev_class, 3);
5723
5724 if (h192 && r192) {
5725 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5726 EIR_SSP_HASH_C192, h192, 16);
5727 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5728 EIR_SSP_RAND_R192, r192, 16);
5729 }
5730
5731 if (h256 && r256) {
5732 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5733 EIR_SSP_HASH_C256, h256, 16);
5734 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5735 EIR_SSP_RAND_R256, r256, 16);
5736 }
5737
5738send_rsp:
5739 mgmt_rp->type = mgmt_cp->type;
5740 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5741
5742 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5743 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5744 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5745 if (err < 0 || status)
5746 goto done;
5747
5748 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5749
5750 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5751 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5752 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5753done:
5754 kfree(mgmt_rp);
5755 mgmt_pending_remove(cmd);
5756}
5757
5758static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5759 struct mgmt_cp_read_local_oob_ext_data *cp)
5760{
5761 struct mgmt_pending_cmd *cmd;
5762 struct hci_request req;
5763 int err;
5764
5765 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5766 cp, sizeof(*cp));
5767 if (!cmd)
5768 return -ENOMEM;
5769
5770 hci_req_init(&req, hdev);
5771
5772 if (bredr_sc_enabled(hdev))
5773 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5774 else
5775 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5776
5777 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5778 if (err < 0) {
5779 mgmt_pending_remove(cmd);
5780 return err;
5781 }
5782
5783 return 0;
5784}
5785
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005786static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5787 void *data, u16 data_len)
5788{
5789 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5790 struct mgmt_rp_read_local_oob_ext_data *rp;
5791 size_t rp_len;
5792 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005793 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005794 int err;
5795
5796 BT_DBG("%s", hdev->name);
5797
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005798 if (hdev_is_powered(hdev)) {
5799 switch (cp->type) {
5800 case BIT(BDADDR_BREDR):
5801 status = mgmt_bredr_support(hdev);
5802 if (status)
5803 eir_len = 0;
5804 else
5805 eir_len = 5;
5806 break;
5807 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5808 status = mgmt_le_support(hdev);
5809 if (status)
5810 eir_len = 0;
5811 else
5812 eir_len = 9 + 3 + 18 + 18 + 3;
5813 break;
5814 default:
5815 status = MGMT_STATUS_INVALID_PARAMS;
5816 eir_len = 0;
5817 break;
5818 }
5819 } else {
5820 status = MGMT_STATUS_NOT_POWERED;
5821 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005822 }
5823
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005824 rp_len = sizeof(*rp) + eir_len;
5825 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005826 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005827 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005828
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005829 if (status)
5830 goto complete;
5831
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005832 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005833
5834 eir_len = 0;
5835 switch (cp->type) {
5836 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005837 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5838 err = read_local_ssp_oob_req(hdev, sk, cp);
5839 hci_dev_unlock(hdev);
5840 if (!err)
5841 goto done;
5842
5843 status = MGMT_STATUS_FAILED;
5844 goto complete;
5845 } else {
5846 eir_len = eir_append_data(rp->eir, eir_len,
5847 EIR_CLASS_OF_DEV,
5848 hdev->dev_class, 3);
5849 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005850 break;
5851 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005852 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5853 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005854 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005855 status = MGMT_STATUS_FAILED;
5856 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005857 }
5858
Marcel Holtmanne2135682015-04-02 12:00:58 -07005859 /* This should return the active RPA, but since the RPA
5860 * is only programmed on demand, it is really hard to fill
5861 * this in at the moment. For now disallow retrieving
5862 * local out-of-band data when privacy is in use.
5863 *
5864 * Returning the identity address will not help here since
5865 * pairing happens before the identity resolving key is
5866 * known and thus the connection establishment happens
5867 * based on the RPA and not the identity address.
5868 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005869 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005870 hci_dev_unlock(hdev);
5871 status = MGMT_STATUS_REJECTED;
5872 goto complete;
5873 }
5874
5875 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5876 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5877 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5878 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005879 memcpy(addr, &hdev->static_addr, 6);
5880 addr[6] = 0x01;
5881 } else {
5882 memcpy(addr, &hdev->bdaddr, 6);
5883 addr[6] = 0x00;
5884 }
5885
5886 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5887 addr, sizeof(addr));
5888
5889 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5890 role = 0x02;
5891 else
5892 role = 0x01;
5893
5894 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5895 &role, sizeof(role));
5896
Marcel Holtmann5082a592015-03-16 12:39:00 -07005897 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5898 eir_len = eir_append_data(rp->eir, eir_len,
5899 EIR_LE_SC_CONFIRM,
5900 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005901
Marcel Holtmann5082a592015-03-16 12:39:00 -07005902 eir_len = eir_append_data(rp->eir, eir_len,
5903 EIR_LE_SC_RANDOM,
5904 rand, sizeof(rand));
5905 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005906
Johan Hedbergf2252572015-11-18 12:49:20 +02005907 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005908
5909 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5910 flags |= LE_AD_NO_BREDR;
5911
5912 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5913 &flags, sizeof(flags));
5914 break;
5915 }
5916
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005917 hci_dev_unlock(hdev);
5918
Marcel Holtmann72000df2015-03-16 16:11:21 -07005919 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5920
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005921 status = MGMT_STATUS_SUCCESS;
5922
5923complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005924 rp->type = cp->type;
5925 rp->eir_len = cpu_to_le16(eir_len);
5926
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005927 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005928 status, rp, sizeof(*rp) + eir_len);
5929 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005930 goto done;
5931
5932 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5933 rp, sizeof(*rp) + eir_len,
5934 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005935
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005936done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005937 kfree(rp);
5938
5939 return err;
5940}
5941
Arman Uguray089fa8c2015-03-25 18:53:45 -07005942static u32 get_supported_adv_flags(struct hci_dev *hdev)
5943{
5944 u32 flags = 0;
5945
5946 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5947 flags |= MGMT_ADV_FLAG_DISCOV;
5948 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5949 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02005950 flags |= MGMT_ADV_FLAG_APPEARANCE;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02005951 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005952
5953 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5954 flags |= MGMT_ADV_FLAG_TX_POWER;
5955
5956 return flags;
5957}
5958
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005959static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5960 void *data, u16 data_len)
5961{
5962 struct mgmt_rp_read_adv_features *rp;
5963 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005964 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005965 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005966 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005967 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005968
5969 BT_DBG("%s", hdev->name);
5970
Arman Uguray089fa8c2015-03-25 18:53:45 -07005971 if (!lmp_le_capable(hdev))
5972 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5973 MGMT_STATUS_REJECTED);
5974
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005975 hci_dev_lock(hdev);
5976
Johan Hedberg02c04af2015-11-26 12:15:58 +02005977 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005978 rp = kmalloc(rp_len, GFP_ATOMIC);
5979 if (!rp) {
5980 hci_dev_unlock(hdev);
5981 return -ENOMEM;
5982 }
5983
Arman Uguray089fa8c2015-03-25 18:53:45 -07005984 supported_flags = get_supported_adv_flags(hdev);
5985
5986 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005987 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5988 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005989 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005990 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005991
Johan Hedberg02c04af2015-11-26 12:15:58 +02005992 instance = rp->instance;
5993 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5994 *instance = adv_instance->instance;
5995 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005996 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005997
5998 hci_dev_unlock(hdev);
5999
6000 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6001 MGMT_STATUS_SUCCESS, rp, rp_len);
6002
6003 kfree(rp);
6004
6005 return err;
6006}
6007
Szymon Janc2bb368702016-09-18 12:50:05 +02006008static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006009{
Arman Uguray4117ed72015-03-23 15:57:14 -07006010 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006011
Marcel Holtmann31a32482015-11-19 16:16:42 +01006012 if (is_adv_data) {
6013 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6014 MGMT_ADV_FLAG_LIMITED_DISCOV |
Szymon Janc2bb368702016-09-18 12:50:05 +02006015 MGMT_ADV_FLAG_MANAGED_FLAGS))
Marcel Holtmann31a32482015-11-19 16:16:42 +01006016 max_len -= 3;
Arman Uguray24b4f382015-03-23 15:57:12 -07006017
Szymon Janc2bb368702016-09-18 12:50:05 +02006018 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
Marcel Holtmann31a32482015-11-19 16:16:42 +01006019 max_len -= 3;
MichaƂ Narajowski7c295c42016-09-18 12:50:02 +02006020 } else {
6021 /* at least 1 byte of name should fit in */
6022 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
6023 max_len -= 3;
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006024
Szymon Janc2bb368702016-09-18 12:50:05 +02006025 if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006026 max_len -= 4;
Arman Uguray5507e352015-03-25 18:53:44 -07006027 }
6028
Szymon Janc2bb368702016-09-18 12:50:05 +02006029 return max_len;
6030}
6031
6032static bool flags_managed(u32 adv_flags)
6033{
6034 return adv_flags & (MGMT_ADV_FLAG_DISCOV |
6035 MGMT_ADV_FLAG_LIMITED_DISCOV |
6036 MGMT_ADV_FLAG_MANAGED_FLAGS);
6037}
6038
6039static bool tx_power_managed(u32 adv_flags)
6040{
6041 return adv_flags & MGMT_ADV_FLAG_TX_POWER;
6042}
6043
6044static bool name_managed(u32 adv_flags)
6045{
6046 return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
6047}
6048
6049static bool appearance_managed(u32 adv_flags)
6050{
6051 return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
6052}
6053
6054static bool tlv_data_is_valid(u32 adv_flags, u8 *data, u8 len, bool is_adv_data)
6055{
6056 int i, cur_len;
6057 u8 max_len;
6058
6059 max_len = tlv_data_max_len(adv_flags, is_adv_data);
6060
Arman Uguray4117ed72015-03-23 15:57:14 -07006061 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006062 return false;
6063
Arman Uguray4117ed72015-03-23 15:57:14 -07006064 /* Make sure that the data is correctly formatted. */
6065 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6066 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006067
Szymon Janc2bb368702016-09-18 12:50:05 +02006068 if (data[i + 1] == EIR_FLAGS && flags_managed(adv_flags))
Arman Ugurayb44133f2015-03-25 18:53:41 -07006069 return false;
6070
Szymon Janc2bb368702016-09-18 12:50:05 +02006071 if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
6072 return false;
6073
6074 if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
6075 return false;
6076
6077 if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
6078 return false;
6079
6080 if (data[i + 1] == EIR_APPEARANCE &&
6081 appearance_managed(adv_flags))
Arman Uguray5507e352015-03-25 18:53:44 -07006082 return false;
6083
Arman Uguray24b4f382015-03-23 15:57:12 -07006084 /* If the current field length would exceed the total data
6085 * length, then it's invalid.
6086 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006087 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006088 return false;
6089 }
6090
6091 return true;
6092}
6093
Arman Uguray24b4f382015-03-23 15:57:12 -07006094static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6095 u16 opcode)
6096{
6097 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006098 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006099 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006100 struct adv_info *adv_instance, *n;
6101 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006102
6103 BT_DBG("status %d", status);
6104
6105 hci_dev_lock(hdev);
6106
6107 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6108
Florian Grandelfffd38b2015-06-18 03:16:47 +02006109 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6110 if (!adv_instance->pending)
6111 continue;
6112
6113 if (!status) {
6114 adv_instance->pending = false;
6115 continue;
6116 }
6117
6118 instance = adv_instance->instance;
6119
6120 if (hdev->cur_adv_instance == instance)
6121 cancel_adv_timeout(hdev);
6122
6123 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006124 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006125 }
6126
6127 if (!cmd)
6128 goto unlock;
6129
Florian Grandelfffd38b2015-06-18 03:16:47 +02006130 cp = cmd->param;
6131 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006132
6133 if (status)
6134 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6135 mgmt_status(status));
6136 else
6137 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6138 mgmt_status(status), &rp, sizeof(rp));
6139
6140 mgmt_pending_remove(cmd);
6141
6142unlock:
6143 hci_dev_unlock(hdev);
6144}
6145
6146static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6147 void *data, u16 data_len)
6148{
6149 struct mgmt_cp_add_advertising *cp = data;
6150 struct mgmt_rp_add_advertising rp;
6151 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006152 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006153 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006154 u16 timeout, duration;
6155 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6156 u8 schedule_instance = 0;
6157 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006158 int err;
6159 struct mgmt_pending_cmd *cmd;
6160 struct hci_request req;
6161
6162 BT_DBG("%s", hdev->name);
6163
6164 status = mgmt_le_support(hdev);
6165 if (status)
6166 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6167 status);
6168
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006169 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6170 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6171 MGMT_STATUS_INVALID_PARAMS);
6172
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006173 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6174 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6175 MGMT_STATUS_INVALID_PARAMS);
6176
Arman Uguray24b4f382015-03-23 15:57:12 -07006177 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006178 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006179 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006180
Florian Grandelfffd38b2015-06-18 03:16:47 +02006181 /* The current implementation only supports a subset of the specified
6182 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006183 */
6184 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006185 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006186 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6187 MGMT_STATUS_INVALID_PARAMS);
6188
6189 hci_dev_lock(hdev);
6190
Arman Uguray912098a2015-03-23 15:57:15 -07006191 if (timeout && !hdev_is_powered(hdev)) {
6192 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6193 MGMT_STATUS_REJECTED);
6194 goto unlock;
6195 }
6196
Arman Uguray24b4f382015-03-23 15:57:12 -07006197 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006198 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006199 pending_find(MGMT_OP_SET_LE, hdev)) {
6200 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6201 MGMT_STATUS_BUSY);
6202 goto unlock;
6203 }
6204
Szymon Janc5e2c59e2016-09-18 12:50:04 +02006205 if (!tlv_data_is_valid(flags, cp->data, cp->adv_data_len, true) ||
6206 !tlv_data_is_valid(flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006207 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006208 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6209 MGMT_STATUS_INVALID_PARAMS);
6210 goto unlock;
6211 }
6212
Florian Grandelfffd38b2015-06-18 03:16:47 +02006213 err = hci_add_adv_instance(hdev, cp->instance, flags,
6214 cp->adv_data_len, cp->data,
6215 cp->scan_rsp_len,
6216 cp->data + cp->adv_data_len,
6217 timeout, duration);
6218 if (err < 0) {
6219 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6220 MGMT_STATUS_FAILED);
6221 goto unlock;
6222 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006223
Florian Grandelfffd38b2015-06-18 03:16:47 +02006224 /* Only trigger an advertising added event if a new instance was
6225 * actually added.
6226 */
6227 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006228 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006229
Florian Grandelfffd38b2015-06-18 03:16:47 +02006230 if (hdev->cur_adv_instance == cp->instance) {
6231 /* If the currently advertised instance is being changed then
6232 * cancel the current advertising and schedule the next
6233 * instance. If there is only one instance then the overridden
6234 * advertising data will be visible right away.
6235 */
6236 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006237
Florian Grandelfffd38b2015-06-18 03:16:47 +02006238 next_instance = hci_get_next_instance(hdev, cp->instance);
6239 if (next_instance)
6240 schedule_instance = next_instance->instance;
6241 } else if (!hdev->adv_instance_timeout) {
6242 /* Immediately advertise the new instance if no other
6243 * instance is currently being advertised.
6244 */
6245 schedule_instance = cp->instance;
6246 }
Arman Uguray912098a2015-03-23 15:57:15 -07006247
Florian Grandelfffd38b2015-06-18 03:16:47 +02006248 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6249 * there is no instance to be advertised then we have no HCI
6250 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006251 */
6252 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006253 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6254 !schedule_instance) {
6255 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006256 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6257 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6258 goto unlock;
6259 }
6260
6261 /* We're good to go, update advertising data, parameters, and start
6262 * advertising.
6263 */
6264 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6265 data_len);
6266 if (!cmd) {
6267 err = -ENOMEM;
6268 goto unlock;
6269 }
6270
6271 hci_req_init(&req, hdev);
6272
Johan Hedbergf2252572015-11-18 12:49:20 +02006273 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006274
Florian Grandelfffd38b2015-06-18 03:16:47 +02006275 if (!err)
6276 err = hci_req_run(&req, add_advertising_complete);
6277
Arman Uguray24b4f382015-03-23 15:57:12 -07006278 if (err < 0)
6279 mgmt_pending_remove(cmd);
6280
6281unlock:
6282 hci_dev_unlock(hdev);
6283
6284 return err;
6285}
6286
Arman Ugurayda9293352015-03-23 15:57:13 -07006287static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6288 u16 opcode)
6289{
6290 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006291 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006292 struct mgmt_rp_remove_advertising rp;
6293
6294 BT_DBG("status %d", status);
6295
6296 hci_dev_lock(hdev);
6297
6298 /* A failure status here only means that we failed to disable
6299 * advertising. Otherwise, the advertising instance has been removed,
6300 * so report success.
6301 */
6302 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6303 if (!cmd)
6304 goto unlock;
6305
Florian Grandel01948332015-06-18 03:16:48 +02006306 cp = cmd->param;
6307 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006308
6309 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6310 &rp, sizeof(rp));
6311 mgmt_pending_remove(cmd);
6312
6313unlock:
6314 hci_dev_unlock(hdev);
6315}
6316
6317static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6318 void *data, u16 data_len)
6319{
6320 struct mgmt_cp_remove_advertising *cp = data;
6321 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006322 struct mgmt_pending_cmd *cmd;
6323 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006324 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006325
6326 BT_DBG("%s", hdev->name);
6327
Arman Ugurayda9293352015-03-23 15:57:13 -07006328 hci_dev_lock(hdev);
6329
Johan Hedberg952497b2015-06-18 21:05:31 +03006330 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006331 err = mgmt_cmd_status(sk, hdev->id,
6332 MGMT_OP_REMOVE_ADVERTISING,
6333 MGMT_STATUS_INVALID_PARAMS);
6334 goto unlock;
6335 }
6336
Arman Ugurayda9293352015-03-23 15:57:13 -07006337 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6338 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6339 pending_find(MGMT_OP_SET_LE, hdev)) {
6340 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6341 MGMT_STATUS_BUSY);
6342 goto unlock;
6343 }
6344
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006345 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006346 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6347 MGMT_STATUS_INVALID_PARAMS);
6348 goto unlock;
6349 }
6350
Florian Grandel01948332015-06-18 03:16:48 +02006351 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006352
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006353 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006354
Florian Grandel01948332015-06-18 03:16:48 +02006355 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006356 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006357
Florian Grandel01948332015-06-18 03:16:48 +02006358 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6359 * flag is set or the device isn't powered then we have no HCI
6360 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006361 */
Florian Grandel01948332015-06-18 03:16:48 +02006362 if (skb_queue_empty(&req.cmd_q) ||
6363 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006364 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006365 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006366 err = mgmt_cmd_complete(sk, hdev->id,
6367 MGMT_OP_REMOVE_ADVERTISING,
6368 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6369 goto unlock;
6370 }
6371
6372 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6373 data_len);
6374 if (!cmd) {
6375 err = -ENOMEM;
6376 goto unlock;
6377 }
6378
Arman Ugurayda9293352015-03-23 15:57:13 -07006379 err = hci_req_run(&req, remove_advertising_complete);
6380 if (err < 0)
6381 mgmt_pending_remove(cmd);
6382
6383unlock:
6384 hci_dev_unlock(hdev);
6385
6386 return err;
6387}
6388
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006389static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6390 void *data, u16 data_len)
6391{
6392 struct mgmt_cp_get_adv_size_info *cp = data;
6393 struct mgmt_rp_get_adv_size_info rp;
6394 u32 flags, supported_flags;
6395 int err;
6396
6397 BT_DBG("%s", hdev->name);
6398
6399 if (!lmp_le_capable(hdev))
6400 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6401 MGMT_STATUS_REJECTED);
6402
6403 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6404 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6405 MGMT_STATUS_INVALID_PARAMS);
6406
6407 flags = __le32_to_cpu(cp->flags);
6408
6409 /* The current implementation only supports a subset of the specified
6410 * flags.
6411 */
6412 supported_flags = get_supported_adv_flags(hdev);
6413 if (flags & ~supported_flags)
6414 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6415 MGMT_STATUS_INVALID_PARAMS);
6416
6417 rp.instance = cp->instance;
6418 rp.flags = cp->flags;
6419 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6420 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6421
6422 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6423 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6424
6425 return err;
6426}
6427
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006428static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006429 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006430 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006431 HCI_MGMT_NO_HDEV |
6432 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006433 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006434 HCI_MGMT_NO_HDEV |
6435 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006436 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006437 HCI_MGMT_NO_HDEV |
6438 HCI_MGMT_UNTRUSTED },
6439 { read_controller_info, MGMT_READ_INFO_SIZE,
6440 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006441 { set_powered, MGMT_SETTING_SIZE },
6442 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6443 { set_connectable, MGMT_SETTING_SIZE },
6444 { set_fast_connectable, MGMT_SETTING_SIZE },
6445 { set_bondable, MGMT_SETTING_SIZE },
6446 { set_link_security, MGMT_SETTING_SIZE },
6447 { set_ssp, MGMT_SETTING_SIZE },
6448 { set_hs, MGMT_SETTING_SIZE },
6449 { set_le, MGMT_SETTING_SIZE },
6450 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6451 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6452 { add_uuid, MGMT_ADD_UUID_SIZE },
6453 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006454 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6455 HCI_MGMT_VAR_LEN },
6456 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6457 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006458 { disconnect, MGMT_DISCONNECT_SIZE },
6459 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6460 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6461 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6462 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6463 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6464 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6465 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6466 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6467 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6468 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6469 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006470 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6471 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6472 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006473 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6474 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6475 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6476 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6477 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6478 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6479 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6480 { set_advertising, MGMT_SETTING_SIZE },
6481 { set_bredr, MGMT_SETTING_SIZE },
6482 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6483 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6484 { set_secure_conn, MGMT_SETTING_SIZE },
6485 { set_debug_keys, MGMT_SETTING_SIZE },
6486 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006487 { load_irks, MGMT_LOAD_IRKS_SIZE,
6488 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006489 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6490 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6491 { add_device, MGMT_ADD_DEVICE_SIZE },
6492 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006493 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6494 HCI_MGMT_VAR_LEN },
6495 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006496 HCI_MGMT_NO_HDEV |
6497 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006498 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006499 HCI_MGMT_UNCONFIGURED |
6500 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006501 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6502 HCI_MGMT_UNCONFIGURED },
6503 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6504 HCI_MGMT_UNCONFIGURED },
6505 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6506 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006507 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006508 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006509 HCI_MGMT_NO_HDEV |
6510 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006511 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006512 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6513 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006514 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006515 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006516 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006517 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6518 HCI_MGMT_UNTRUSTED },
MichaƂ Narajowskic4960ec2016-09-18 12:50:03 +02006519 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006520};
6521
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006522void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006523{
Marcel Holtmannced85542015-03-14 19:27:56 -07006524 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006525
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006526 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6527 return;
6528
Marcel Holtmannf9207332015-03-14 19:27:55 -07006529 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006530 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006531 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6532 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6533 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006534 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006535 } else {
6536 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6537 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006538 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006539 }
6540 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006541 case HCI_AMP:
6542 ev.type = 0x02;
6543 break;
6544 default:
6545 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006546 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006547
6548 ev.bus = hdev->bus;
6549
6550 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6551 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006552}
6553
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006554void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006555{
Marcel Holtmannced85542015-03-14 19:27:56 -07006556 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006557 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006558
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006559 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6560 return;
6561
Marcel Holtmannf9207332015-03-14 19:27:55 -07006562 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006563 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006564 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006565
Marcel Holtmannf9207332015-03-14 19:27:55 -07006566 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6567 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6568 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006569 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006570 } else {
6571 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6572 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006573 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006574 }
6575 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006576 case HCI_AMP:
6577 ev.type = 0x02;
6578 break;
6579 default:
6580 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006581 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006582
6583 ev.bus = hdev->bus;
6584
6585 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6586 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006587}
6588
Andre Guedes6046dc32014-02-26 20:21:51 -03006589/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006590static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006591{
6592 struct hci_conn_params *p;
6593
6594 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006595 /* Needed for AUTO_OFF case where might not "really"
6596 * have been powered off.
6597 */
6598 list_del_init(&p->action);
6599
6600 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006601 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006602 case HCI_AUTO_CONN_ALWAYS:
6603 list_add(&p->action, &hdev->pend_le_conns);
6604 break;
6605 case HCI_AUTO_CONN_REPORT:
6606 list_add(&p->action, &hdev->pend_le_reports);
6607 break;
6608 default:
6609 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006610 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006611 }
6612}
6613
Johan Hedberg2ff13892015-11-25 16:15:44 +02006614void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006615{
6616 struct cmd_lookup match = { NULL, hdev };
6617
Johan Hedberg2ff13892015-11-25 16:15:44 +02006618 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006619
Johan Hedberg2ff13892015-11-25 16:15:44 +02006620 hci_dev_lock(hdev);
6621
6622 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006623 restart_le_actions(hdev);
6624 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006625 }
6626
Johan Hedberg229ab392013-03-15 17:06:53 -05006627 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6628
6629 new_settings(hdev, match.sk);
6630
Johan Hedberg229ab392013-03-15 17:06:53 -05006631 if (match.sk)
6632 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006633
6634 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006635}
6636
Johan Hedberg2ff13892015-11-25 16:15:44 +02006637void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006638{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006639 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006640 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006641
Johan Hedberg229ab392013-03-15 17:06:53 -05006642 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006643
6644 /* If the power off is because of hdev unregistration let
6645 * use the appropriate INVALID_INDEX status. Otherwise use
6646 * NOT_POWERED. We cover both scenarios here since later in
6647 * mgmt_index_removed() any hci_conn callbacks will have already
6648 * been triggered, potentially causing misleading DISCONNECTED
6649 * status responses.
6650 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006651 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006652 status = MGMT_STATUS_INVALID_INDEX;
6653 else
6654 status = MGMT_STATUS_NOT_POWERED;
6655
6656 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006657
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006658 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02006659 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6660 zero_cod, sizeof(zero_cod),
6661 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006662 ext_info_changed(hdev, NULL);
6663 }
Johan Hedberg229ab392013-03-15 17:06:53 -05006664
Johan Hedberg2ff13892015-11-25 16:15:44 +02006665 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006666
6667 if (match.sk)
6668 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006669}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006670
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006671void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006672{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006673 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006674 u8 status;
6675
Johan Hedberg333ae952015-03-17 13:48:47 +02006676 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006677 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006678 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006679
6680 if (err == -ERFKILL)
6681 status = MGMT_STATUS_RFKILLED;
6682 else
6683 status = MGMT_STATUS_FAILED;
6684
Johan Hedberga69e8372015-03-06 21:08:53 +02006685 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006686
6687 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006688}
6689
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006690void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6691 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006692{
Johan Hedberg86742e12011-11-07 23:13:38 +02006693 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006694
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006695 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006696
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006697 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006698 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006699 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006700 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006701 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006702 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006703
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006704 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006705}
Johan Hedbergf7520542011-01-20 12:34:39 +02006706
Johan Hedbergd7b25452014-05-23 13:19:53 +03006707static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6708{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006709 switch (ltk->type) {
6710 case SMP_LTK:
6711 case SMP_LTK_SLAVE:
6712 if (ltk->authenticated)
6713 return MGMT_LTK_AUTHENTICATED;
6714 return MGMT_LTK_UNAUTHENTICATED;
6715 case SMP_LTK_P256:
6716 if (ltk->authenticated)
6717 return MGMT_LTK_P256_AUTH;
6718 return MGMT_LTK_P256_UNAUTH;
6719 case SMP_LTK_P256_DEBUG:
6720 return MGMT_LTK_P256_DEBUG;
6721 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006722
6723 return MGMT_LTK_UNAUTHENTICATED;
6724}
6725
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006726void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006727{
6728 struct mgmt_ev_new_long_term_key ev;
6729
6730 memset(&ev, 0, sizeof(ev));
6731
Marcel Holtmann5192d302014-02-19 17:11:58 -08006732 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006733 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006734 * to store long term keys. Their addresses will change the
6735 * next time around.
6736 *
6737 * Only when a remote device provides an identity address
6738 * make sure the long term key is stored. If the remote
6739 * identity is known, the long term keys are internally
6740 * mapped to the identity address. So allow static random
6741 * and public addresses here.
6742 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006743 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6744 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6745 ev.store_hint = 0x00;
6746 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006747 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006748
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006749 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006750 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006751 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006752 ev.key.enc_size = key->enc_size;
6753 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006754 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006755
Johan Hedberg2ceba532014-06-16 19:25:16 +03006756 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006757 ev.key.master = 1;
6758
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006759 /* Make sure we copy only the significant bytes based on the
6760 * encryption key size, and set the rest of the value to zeroes.
6761 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006762 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006763 memset(ev.key.val + key->enc_size, 0,
6764 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006765
Marcel Holtmann083368f2013-10-15 14:26:29 -07006766 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006767}
6768
Johan Hedbergcad20c22015-10-12 13:36:19 +02006769void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006770{
6771 struct mgmt_ev_new_irk ev;
6772
6773 memset(&ev, 0, sizeof(ev));
6774
Johan Hedbergcad20c22015-10-12 13:36:19 +02006775 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006776
Johan Hedberg95fbac82014-02-19 15:18:31 +02006777 bacpy(&ev.rpa, &irk->rpa);
6778 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6779 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6780 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6781
6782 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6783}
6784
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006785void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6786 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006787{
6788 struct mgmt_ev_new_csrk ev;
6789
6790 memset(&ev, 0, sizeof(ev));
6791
6792 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006793 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006794 * to store signature resolving keys. Their addresses will change
6795 * the next time around.
6796 *
6797 * Only when a remote device provides an identity address
6798 * make sure the signature resolving key is stored. So allow
6799 * static random and public addresses here.
6800 */
6801 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6802 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6803 ev.store_hint = 0x00;
6804 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006805 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006806
6807 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6808 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006809 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006810 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6811
6812 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6813}
6814
Andre Guedesffb5a8272014-07-01 18:10:11 -03006815void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006816 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6817 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006818{
6819 struct mgmt_ev_new_conn_param ev;
6820
Johan Hedbergc103aea2014-07-02 17:37:34 +03006821 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6822 return;
6823
Andre Guedesffb5a8272014-07-01 18:10:11 -03006824 memset(&ev, 0, sizeof(ev));
6825 bacpy(&ev.addr.bdaddr, bdaddr);
6826 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006827 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006828 ev.min_interval = cpu_to_le16(min_interval);
6829 ev.max_interval = cpu_to_le16(max_interval);
6830 ev.latency = cpu_to_le16(latency);
6831 ev.timeout = cpu_to_le16(timeout);
6832
6833 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6834}
6835
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006836void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6837 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006838{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006839 char buf[512];
6840 struct mgmt_ev_device_connected *ev = (void *) buf;
6841 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006842
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006843 bacpy(&ev->addr.bdaddr, &conn->dst);
6844 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006845
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006846 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006847
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006848 /* We must ensure that the EIR Data fields are ordered and
6849 * unique. Keep it simple for now and avoid the problem by not
6850 * adding any BR/EDR data to the LE adv.
6851 */
6852 if (conn->le_adv_data_len > 0) {
6853 memcpy(&ev->eir[eir_len],
6854 conn->le_adv_data, conn->le_adv_data_len);
6855 eir_len = conn->le_adv_data_len;
6856 } else {
6857 if (name_len > 0)
6858 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6859 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006860
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006861 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006862 eir_len = eir_append_data(ev->eir, eir_len,
6863 EIR_CLASS_OF_DEV,
6864 conn->dev_class, 3);
6865 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006866
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006867 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006868
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006869 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6870 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006871}
6872
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006873static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006874{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006875 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006876
Johan Hedbergf5818c22014-12-05 13:36:02 +02006877 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006878
6879 *sk = cmd->sk;
6880 sock_hold(*sk);
6881
Johan Hedberga664b5b2011-02-19 12:06:02 -03006882 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006883}
6884
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006885static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006886{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006887 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006888 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006889
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006890 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6891
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006892 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006893 mgmt_pending_remove(cmd);
6894}
6895
Johan Hedberg84c61d92014-08-01 11:13:30 +03006896bool mgmt_powering_down(struct hci_dev *hdev)
6897{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006898 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006899 struct mgmt_mode *cp;
6900
Johan Hedberg333ae952015-03-17 13:48:47 +02006901 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006902 if (!cmd)
6903 return false;
6904
6905 cp = cmd->param;
6906 if (!cp->val)
6907 return true;
6908
6909 return false;
6910}
6911
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006912void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006913 u8 link_type, u8 addr_type, u8 reason,
6914 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006915{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006916 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006917 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006918
Johan Hedberg84c61d92014-08-01 11:13:30 +03006919 /* The connection is still in hci_conn_hash so test for 1
6920 * instead of 0 to know if this is the last one.
6921 */
6922 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6923 cancel_delayed_work(&hdev->power_off);
6924 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006925 }
6926
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006927 if (!mgmt_connected)
6928 return;
6929
Andre Guedes57eb7762013-10-30 19:01:41 -03006930 if (link_type != ACL_LINK && link_type != LE_LINK)
6931 return;
6932
Johan Hedberg744cf192011-11-08 20:40:14 +02006933 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006934
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006935 bacpy(&ev.addr.bdaddr, bdaddr);
6936 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6937 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006938
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006939 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006940
6941 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006942 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006943
Johan Hedberg124f6e32012-02-09 13:50:12 +02006944 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006945 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006946}
6947
Marcel Holtmann78929242013-10-06 23:55:47 -07006948void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6949 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006950{
Andre Guedes3655bba2013-10-30 19:01:40 -03006951 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6952 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006953 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006954
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006955 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6956 hdev);
6957
Johan Hedberg333ae952015-03-17 13:48:47 +02006958 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006959 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006960 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006961
Andre Guedes3655bba2013-10-30 19:01:40 -03006962 cp = cmd->param;
6963
6964 if (bacmp(bdaddr, &cp->addr.bdaddr))
6965 return;
6966
6967 if (cp->addr.type != bdaddr_type)
6968 return;
6969
Johan Hedbergf5818c22014-12-05 13:36:02 +02006970 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006971 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006972}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006973
Marcel Holtmann445608d2013-10-06 23:55:48 -07006974void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6975 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006976{
6977 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006978
Johan Hedberg84c61d92014-08-01 11:13:30 +03006979 /* The connection is still in hci_conn_hash so test for 1
6980 * instead of 0 to know if this is the last one.
6981 */
6982 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6983 cancel_delayed_work(&hdev->power_off);
6984 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006985 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006986
Johan Hedberg4c659c32011-11-07 23:13:39 +02006987 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006988 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006989 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006990
Marcel Holtmann445608d2013-10-06 23:55:48 -07006991 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006992}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006993
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006994void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006995{
6996 struct mgmt_ev_pin_code_request ev;
6997
Johan Hedbergd8457692012-02-17 14:24:57 +02006998 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006999 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007000 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007001
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007002 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007003}
7004
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007005void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7006 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007007{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007008 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007009
Johan Hedberg333ae952015-03-17 13:48:47 +02007010 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007011 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007012 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007013
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007014 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007015 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007016}
7017
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007018void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7019 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007020{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007021 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007022
Johan Hedberg333ae952015-03-17 13:48:47 +02007023 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007024 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007025 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007026
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007027 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007028 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007029}
Johan Hedberga5c29682011-02-19 12:05:57 -03007030
Johan Hedberg744cf192011-11-08 20:40:14 +02007031int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007032 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007033 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007034{
7035 struct mgmt_ev_user_confirm_request ev;
7036
Johan Hedberg744cf192011-11-08 20:40:14 +02007037 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007038
Johan Hedberg272d90d2012-02-09 15:26:12 +02007039 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007040 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007041 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007042 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007043
Johan Hedberg744cf192011-11-08 20:40:14 +02007044 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007045 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007046}
7047
Johan Hedberg272d90d2012-02-09 15:26:12 +02007048int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007049 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007050{
7051 struct mgmt_ev_user_passkey_request ev;
7052
7053 BT_DBG("%s", hdev->name);
7054
Johan Hedberg272d90d2012-02-09 15:26:12 +02007055 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007056 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007057
7058 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007059 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007060}
7061
Brian Gix0df4c182011-11-16 13:53:13 -08007062static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007063 u8 link_type, u8 addr_type, u8 status,
7064 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007065{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007066 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007067
Johan Hedberg333ae952015-03-17 13:48:47 +02007068 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007069 if (!cmd)
7070 return -ENOENT;
7071
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007072 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007073 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007074
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007075 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007076}
7077
Johan Hedberg744cf192011-11-08 20:40:14 +02007078int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007079 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007080{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007081 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007082 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007083}
7084
Johan Hedberg272d90d2012-02-09 15:26:12 +02007085int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007086 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007087{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007088 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007089 status,
7090 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007091}
Johan Hedberg2a611692011-02-19 12:06:00 -03007092
Brian Gix604086b2011-11-23 08:28:33 -08007093int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007094 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007095{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007096 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007097 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007098}
7099
Johan Hedberg272d90d2012-02-09 15:26:12 +02007100int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007101 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007102{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007103 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007104 status,
7105 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007106}
7107
Johan Hedberg92a25252012-09-06 18:39:26 +03007108int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7109 u8 link_type, u8 addr_type, u32 passkey,
7110 u8 entered)
7111{
7112 struct mgmt_ev_passkey_notify ev;
7113
7114 BT_DBG("%s", hdev->name);
7115
7116 bacpy(&ev.addr.bdaddr, bdaddr);
7117 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7118 ev.passkey = __cpu_to_le32(passkey);
7119 ev.entered = entered;
7120
7121 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7122}
7123
Johan Hedberge1e930f2014-09-08 17:09:49 -07007124void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007125{
7126 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007127 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007128 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007129
Johan Hedberge1e930f2014-09-08 17:09:49 -07007130 bacpy(&ev.addr.bdaddr, &conn->dst);
7131 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7132 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007133
Johan Hedberge1e930f2014-09-08 17:09:49 -07007134 cmd = find_pairing(conn);
7135
7136 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7137 cmd ? cmd->sk : NULL);
7138
Johan Hedberga511b352014-12-11 21:45:45 +02007139 if (cmd) {
7140 cmd->cmd_complete(cmd, status);
7141 mgmt_pending_remove(cmd);
7142 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007143}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007144
Marcel Holtmann464996a2013-10-15 14:26:24 -07007145void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007146{
7147 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007148 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007149
7150 if (status) {
7151 u8 mgmt_err = mgmt_status(status);
7152 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007153 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007154 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007155 }
7156
Marcel Holtmann464996a2013-10-15 14:26:24 -07007157 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007158 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007159 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007160 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007161
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007162 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007163 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007164
Johan Hedberg47990ea2012-02-22 11:58:37 +02007165 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007166 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007167
7168 if (match.sk)
7169 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007170}
7171
Johan Hedberg890ea892013-03-15 17:06:52 -05007172static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007173{
Johan Hedberg890ea892013-03-15 17:06:52 -05007174 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007175 struct hci_cp_write_eir cp;
7176
Johan Hedberg976eb202012-10-24 21:12:01 +03007177 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007178 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007179
Johan Hedbergc80da272012-02-22 15:38:48 +02007180 memset(hdev->eir, 0, sizeof(hdev->eir));
7181
Johan Hedbergcacaf522012-02-21 00:52:42 +02007182 memset(&cp, 0, sizeof(cp));
7183
Johan Hedberg890ea892013-03-15 17:06:52 -05007184 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007185}
7186
Marcel Holtmann3e248562013-10-15 14:26:25 -07007187void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007188{
7189 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007190 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007191 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007192
7193 if (status) {
7194 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007195
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007196 if (enable && hci_dev_test_and_clear_flag(hdev,
7197 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007198 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007199 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007200 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007201
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007202 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7203 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007204 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007205 }
7206
7207 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007208 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007209 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007210 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007211 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007212 changed = hci_dev_test_and_clear_flag(hdev,
7213 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007214 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007215 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007216 }
7217
7218 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7219
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007220 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007221 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007222
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007223 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007224 sock_put(match.sk);
7225
Johan Hedberg890ea892013-03-15 17:06:52 -05007226 hci_req_init(&req, hdev);
7227
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007228 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7229 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007230 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7231 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007232 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007233 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007234 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007235 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007236
7237 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007238}
7239
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007240static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007241{
7242 struct cmd_lookup *match = data;
7243
Johan Hedberg90e70452012-02-23 23:09:40 +02007244 if (match->sk == NULL) {
7245 match->sk = cmd->sk;
7246 sock_hold(match->sk);
7247 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007248}
7249
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007250void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7251 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007252{
Johan Hedberg90e70452012-02-23 23:09:40 +02007253 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007254
Johan Hedberg92da6092013-03-15 17:06:55 -05007255 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7256 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7257 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007258
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007259 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007260 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7261 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007262 ext_info_changed(hdev, NULL);
7263 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007264
7265 if (match.sk)
7266 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007267}
7268
Marcel Holtmann7667da32013-10-15 14:26:27 -07007269void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007270{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007271 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007272 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007273
Johan Hedberg13928972013-03-15 17:07:00 -05007274 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007275 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007276
7277 memset(&ev, 0, sizeof(ev));
7278 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007279 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007280
Johan Hedberg333ae952015-03-17 13:48:47 +02007281 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007282 if (!cmd) {
7283 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007284
Johan Hedberg13928972013-03-15 17:07:00 -05007285 /* If this is a HCI command related to powering on the
7286 * HCI dev don't send any mgmt signals.
7287 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007288 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007289 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007290 }
7291
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007292 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7293 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007294 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007295}
Szymon Jancc35938b2011-03-22 13:12:21 +01007296
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007297static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7298{
7299 int i;
7300
7301 for (i = 0; i < uuid_count; i++) {
7302 if (!memcmp(uuid, uuids[i], 16))
7303 return true;
7304 }
7305
7306 return false;
7307}
7308
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007309static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7310{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007311 u16 parsed = 0;
7312
7313 while (parsed < eir_len) {
7314 u8 field_len = eir[0];
7315 u8 uuid[16];
7316 int i;
7317
7318 if (field_len == 0)
7319 break;
7320
7321 if (eir_len - parsed < field_len + 1)
7322 break;
7323
7324 switch (eir[1]) {
7325 case EIR_UUID16_ALL:
7326 case EIR_UUID16_SOME:
7327 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007328 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007329 uuid[13] = eir[i + 3];
7330 uuid[12] = eir[i + 2];
7331 if (has_uuid(uuid, uuid_count, uuids))
7332 return true;
7333 }
7334 break;
7335 case EIR_UUID32_ALL:
7336 case EIR_UUID32_SOME:
7337 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007338 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007339 uuid[15] = eir[i + 5];
7340 uuid[14] = eir[i + 4];
7341 uuid[13] = eir[i + 3];
7342 uuid[12] = eir[i + 2];
7343 if (has_uuid(uuid, uuid_count, uuids))
7344 return true;
7345 }
7346 break;
7347 case EIR_UUID128_ALL:
7348 case EIR_UUID128_SOME:
7349 for (i = 0; i + 17 <= field_len; i += 16) {
7350 memcpy(uuid, eir + i + 2, 16);
7351 if (has_uuid(uuid, uuid_count, uuids))
7352 return true;
7353 }
7354 break;
7355 }
7356
7357 parsed += field_len + 1;
7358 eir += field_len + 1;
7359 }
7360
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007361 return false;
7362}
7363
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007364static void restart_le_scan(struct hci_dev *hdev)
7365{
7366 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007367 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007368 return;
7369
7370 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7371 hdev->discovery.scan_start +
7372 hdev->discovery.scan_duration))
7373 return;
7374
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007375 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007376 DISCOV_LE_RESTART_DELAY);
7377}
7378
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007379static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7380 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7381{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007382 /* If a RSSI threshold has been specified, and
7383 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7384 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7385 * is set, let it through for further processing, as we might need to
7386 * restart the scan.
7387 *
7388 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7389 * the results are also dropped.
7390 */
7391 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7392 (rssi == HCI_RSSI_INVALID ||
7393 (rssi < hdev->discovery.rssi &&
7394 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7395 return false;
7396
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007397 if (hdev->discovery.uuid_count != 0) {
7398 /* If a list of UUIDs is provided in filter, results with no
7399 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007400 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007401 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7402 hdev->discovery.uuids) &&
7403 !eir_has_uuids(scan_rsp, scan_rsp_len,
7404 hdev->discovery.uuid_count,
7405 hdev->discovery.uuids))
7406 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007407 }
7408
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007409 /* If duplicate filtering does not report RSSI changes, then restart
7410 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007411 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007412 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7413 restart_le_scan(hdev);
7414
7415 /* Validate RSSI value against the RSSI threshold once more. */
7416 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7417 rssi < hdev->discovery.rssi)
7418 return false;
7419 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007420
7421 return true;
7422}
7423
Marcel Holtmann901801b2013-10-06 23:55:51 -07007424void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007425 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7426 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007427{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007428 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007429 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007430 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007431
Johan Hedberg75ce2082014-07-02 22:42:01 +03007432 /* Don't send events for a non-kernel initiated discovery. With
7433 * LE one exception is if we have pend_le_reports > 0 in which
7434 * case we're doing passive scanning and want these events.
7435 */
7436 if (!hci_discovery_active(hdev)) {
7437 if (link_type == ACL_LINK)
7438 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007439 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007440 return;
7441 }
Andre Guedes12602d02013-04-30 15:29:40 -03007442
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007443 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007444 /* We are using service discovery */
7445 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7446 scan_rsp_len))
7447 return;
7448 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007449
Johan Hedberg78b781c2016-01-05 13:19:32 +02007450 if (hdev->discovery.limited) {
7451 /* Check for limited discoverable bit */
7452 if (dev_class) {
7453 if (!(dev_class[1] & 0x20))
7454 return;
7455 } else {
7456 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7457 if (!flags || !(flags[0] & LE_AD_LIMITED))
7458 return;
7459 }
7460 }
7461
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007462 /* Make sure that the buffer is big enough. The 5 extra bytes
7463 * are for the potential CoD field.
7464 */
7465 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007466 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007467
Johan Hedberg1dc06092012-01-15 21:01:23 +02007468 memset(buf, 0, sizeof(buf));
7469
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007470 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7471 * RSSI value was reported as 0 when not available. This behavior
7472 * is kept when using device discovery. This is required for full
7473 * backwards compatibility with the API.
7474 *
7475 * However when using service discovery, the value 127 will be
7476 * returned when the RSSI is not available.
7477 */
Szymon Janc91200e92015-01-22 16:57:05 +01007478 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7479 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007480 rssi = 0;
7481
Johan Hedberg841c5642014-07-07 12:45:54 +03007482 bacpy(&ev->addr.bdaddr, bdaddr);
7483 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007484 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007485 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007486
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007487 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007488 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007489 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007490
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007491 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7492 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007493 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007494 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007495
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007496 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007497 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007498 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007499
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007500 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7501 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007502
Marcel Holtmann901801b2013-10-06 23:55:51 -07007503 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007504}
Johan Hedberga88a9652011-03-30 13:18:12 +03007505
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007506void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7507 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007508{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007509 struct mgmt_ev_device_found *ev;
7510 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7511 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007512
Johan Hedbergb644ba32012-01-17 21:48:47 +02007513 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007514
Johan Hedbergb644ba32012-01-17 21:48:47 +02007515 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007516
Johan Hedbergb644ba32012-01-17 21:48:47 +02007517 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007518 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007519 ev->rssi = rssi;
7520
7521 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007522 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007523
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007524 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007525
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007526 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007527}
Johan Hedberg314b2382011-04-27 10:29:57 -04007528
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007529void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007530{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007531 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007532
Andre Guedes343fb142011-11-22 17:14:19 -03007533 BT_DBG("%s discovering %u", hdev->name, discovering);
7534
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007535 memset(&ev, 0, sizeof(ev));
7536 ev.type = hdev->discovery.type;
7537 ev.discovering = discovering;
7538
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007539 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007540}
Antti Julku5e762442011-08-25 16:48:02 +03007541
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007542static struct hci_mgmt_chan chan = {
7543 .channel = HCI_CHANNEL_CONTROL,
7544 .handler_count = ARRAY_SIZE(mgmt_handlers),
7545 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007546 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007547};
7548
7549int mgmt_init(void)
7550{
7551 return hci_mgmt_chan_register(&chan);
7552}
7553
7554void mgmt_exit(void)
7555{
7556 hci_mgmt_chan_unregister(&chan);
7557}