blob: 6d0f0025052fab5c3df7707f2e01ef3ece2be8a8 [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 Hedbergdc4270c2015-11-23 15:07:51 +020041#define MGMT_REVISION 11
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 Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
108static const u16 mgmt_events[] = {
109 MGMT_EV_CONTROLLER_ERROR,
110 MGMT_EV_INDEX_ADDED,
111 MGMT_EV_INDEX_REMOVED,
112 MGMT_EV_NEW_SETTINGS,
113 MGMT_EV_CLASS_OF_DEV_CHANGED,
114 MGMT_EV_LOCAL_NAME_CHANGED,
115 MGMT_EV_NEW_LINK_KEY,
116 MGMT_EV_NEW_LONG_TERM_KEY,
117 MGMT_EV_DEVICE_CONNECTED,
118 MGMT_EV_DEVICE_DISCONNECTED,
119 MGMT_EV_CONNECT_FAILED,
120 MGMT_EV_PIN_CODE_REQUEST,
121 MGMT_EV_USER_CONFIRM_REQUEST,
122 MGMT_EV_USER_PASSKEY_REQUEST,
123 MGMT_EV_AUTH_FAILED,
124 MGMT_EV_DEVICE_FOUND,
125 MGMT_EV_DISCOVERING,
126 MGMT_EV_DEVICE_BLOCKED,
127 MGMT_EV_DEVICE_UNBLOCKED,
128 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300129 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800130 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700131 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200132 MGMT_EV_DEVICE_ADDED,
133 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300134 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200135 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200136 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200137 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700138 MGMT_EV_EXT_INDEX_ADDED,
139 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700140 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700141 MGMT_EV_ADVERTISING_ADDED,
142 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200143};
144
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700145static const u16 mgmt_untrusted_commands[] = {
146 MGMT_OP_READ_INDEX_LIST,
147 MGMT_OP_READ_INFO,
148 MGMT_OP_READ_UNCONF_INDEX_LIST,
149 MGMT_OP_READ_CONFIG_INFO,
150 MGMT_OP_READ_EXT_INDEX_LIST,
151};
152
153static const u16 mgmt_untrusted_events[] = {
154 MGMT_EV_INDEX_ADDED,
155 MGMT_EV_INDEX_REMOVED,
156 MGMT_EV_NEW_SETTINGS,
157 MGMT_EV_CLASS_OF_DEV_CHANGED,
158 MGMT_EV_LOCAL_NAME_CHANGED,
159 MGMT_EV_UNCONF_INDEX_ADDED,
160 MGMT_EV_UNCONF_INDEX_REMOVED,
161 MGMT_EV_NEW_CONFIG_OPTIONS,
162 MGMT_EV_EXT_INDEX_ADDED,
163 MGMT_EV_EXT_INDEX_REMOVED,
164};
165
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800166#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200167
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200168#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
169 "\x00\x00\x00\x00\x00\x00\x00\x00"
170
Johan Hedbergca69b792011-11-11 18:10:00 +0200171/* HCI to MGMT error code conversion table */
172static u8 mgmt_status_table[] = {
173 MGMT_STATUS_SUCCESS,
174 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
175 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
176 MGMT_STATUS_FAILED, /* Hardware Failure */
177 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
178 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200179 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200180 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
181 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
182 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
184 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
185 MGMT_STATUS_BUSY, /* Command Disallowed */
186 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
187 MGMT_STATUS_REJECTED, /* Rejected Security */
188 MGMT_STATUS_REJECTED, /* Rejected Personal */
189 MGMT_STATUS_TIMEOUT, /* Host Timeout */
190 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
191 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
192 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
193 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
194 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
195 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
196 MGMT_STATUS_BUSY, /* Repeated Attempts */
197 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
198 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
199 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
200 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
201 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
202 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
203 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
204 MGMT_STATUS_FAILED, /* Unspecified Error */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
206 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
207 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
208 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
209 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
210 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
211 MGMT_STATUS_FAILED, /* Unit Link Key Used */
212 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
213 MGMT_STATUS_TIMEOUT, /* Instant Passed */
214 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
215 MGMT_STATUS_FAILED, /* Transaction Collision */
216 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
217 MGMT_STATUS_REJECTED, /* QoS Rejected */
218 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
219 MGMT_STATUS_REJECTED, /* Insufficient Security */
220 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
221 MGMT_STATUS_BUSY, /* Role Switch Pending */
222 MGMT_STATUS_FAILED, /* Slot Violation */
223 MGMT_STATUS_FAILED, /* Role Switch Failed */
224 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
225 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
226 MGMT_STATUS_BUSY, /* Host Busy Pairing */
227 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
228 MGMT_STATUS_BUSY, /* Controller Busy */
229 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
230 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
231 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
232 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
233 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
234};
235
236static u8 mgmt_status(u8 hci_status)
237{
238 if (hci_status < ARRAY_SIZE(mgmt_status_table))
239 return mgmt_status_table[hci_status];
240
241 return MGMT_STATUS_FAILED;
242}
243
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700244static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
245 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700246{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700247 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
248 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700249}
250
Marcel Holtmann72000df2015-03-16 16:11:21 -0700251static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
252 u16 len, int flag, struct sock *skip_sk)
253{
254 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
255 flag, skip_sk);
256}
257
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700258static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
259 u16 len, struct sock *skip_sk)
260{
261 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
262 HCI_MGMT_GENERIC_EVENTS, skip_sk);
263}
264
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200265static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
266 struct sock *skip_sk)
267{
268 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700269 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200270}
271
Johan Hedberg85813a72015-10-21 18:02:59 +0300272static u8 le_addr_type(u8 mgmt_addr_type)
273{
274 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
275 return ADDR_LE_DEV_PUBLIC;
276 else
277 return ADDR_LE_DEV_RANDOM;
278}
279
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300280static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
281 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200282{
283 struct mgmt_rp_read_version rp;
284
285 BT_DBG("sock %p", sk);
286
287 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700288 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200289
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200290 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
291 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200292}
293
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300294static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
295 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296{
297 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700298 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200299 size_t rp_size;
300 int i, err;
301
302 BT_DBG("sock %p", sk);
303
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
305 num_commands = ARRAY_SIZE(mgmt_commands);
306 num_events = ARRAY_SIZE(mgmt_events);
307 } else {
308 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
309 num_events = ARRAY_SIZE(mgmt_untrusted_events);
310 }
311
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
313
314 rp = kmalloc(rp_size, GFP_KERNEL);
315 if (!rp)
316 return -ENOMEM;
317
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700318 rp->num_commands = cpu_to_le16(num_commands);
319 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700321 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
322 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200323
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700324 for (i = 0; i < num_commands; i++, opcode++)
325 put_unaligned_le16(mgmt_commands[i], opcode);
326
327 for (i = 0; i < num_events; i++, opcode++)
328 put_unaligned_le16(mgmt_events[i], opcode);
329 } else {
330 __le16 *opcode = rp->opcodes;
331
332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
337 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200338
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200339 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
340 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200341 kfree(rp);
342
343 return err;
344}
345
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300346static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
347 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200351 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
355 BT_DBG("sock %p", sk);
356
357 read_lock(&hci_dev_list_lock);
358
359 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300360 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200361 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700362 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700363 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364 }
365
Johan Hedberga38528f2011-01-22 06:46:43 +0200366 rp_len = sizeof(*rp) + (2 * count);
367 rp = kmalloc(rp_len, GFP_ATOMIC);
368 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100369 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100371 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372
Johan Hedberg476e44c2012-10-19 20:10:46 +0300373 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200374 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700375 if (hci_dev_test_flag(d, HCI_SETUP) ||
376 hci_dev_test_flag(d, HCI_CONFIG) ||
377 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200378 continue;
379
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200380 /* Devices marked as raw-only are neither configured
381 * nor unconfigured controllers.
382 */
383 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700387 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700388 rp->index[count++] = cpu_to_le16(d->id);
389 BT_DBG("Added hci%u", d->id);
390 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391 }
392
Johan Hedberg476e44c2012-10-19 20:10:46 +0300393 rp->num_controllers = cpu_to_le16(count);
394 rp_len = sizeof(*rp) + (2 * count);
395
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 read_unlock(&hci_dev_list_lock);
397
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200398 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
399 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400
Johan Hedberga38528f2011-01-22 06:46:43 +0200401 kfree(rp);
402
403 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404}
405
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200406static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
407 void *data, u16 data_len)
408{
409 struct mgmt_rp_read_unconf_index_list *rp;
410 struct hci_dev *d;
411 size_t rp_len;
412 u16 count;
413 int err;
414
415 BT_DBG("sock %p", sk);
416
417 read_lock(&hci_dev_list_lock);
418
419 count = 0;
420 list_for_each_entry(d, &hci_dev_list, list) {
421 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700422 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200423 count++;
424 }
425
426 rp_len = sizeof(*rp) + (2 * count);
427 rp = kmalloc(rp_len, GFP_ATOMIC);
428 if (!rp) {
429 read_unlock(&hci_dev_list_lock);
430 return -ENOMEM;
431 }
432
433 count = 0;
434 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700435 if (hci_dev_test_flag(d, HCI_SETUP) ||
436 hci_dev_test_flag(d, HCI_CONFIG) ||
437 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438 continue;
439
440 /* Devices marked as raw-only are neither configured
441 * nor unconfigured controllers.
442 */
443 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
444 continue;
445
446 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700447 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448 rp->index[count++] = cpu_to_le16(d->id);
449 BT_DBG("Added hci%u", d->id);
450 }
451 }
452
453 rp->num_controllers = cpu_to_le16(count);
454 rp_len = sizeof(*rp) + (2 * count);
455
456 read_unlock(&hci_dev_list_lock);
457
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200458 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
459 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200460
461 kfree(rp);
462
463 return err;
464}
465
Marcel Holtmann96f14742015-03-14 19:27:57 -0700466static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
467 void *data, u16 data_len)
468{
469 struct mgmt_rp_read_ext_index_list *rp;
470 struct hci_dev *d;
471 size_t rp_len;
472 u16 count;
473 int err;
474
475 BT_DBG("sock %p", sk);
476
477 read_lock(&hci_dev_list_lock);
478
479 count = 0;
480 list_for_each_entry(d, &hci_dev_list, list) {
481 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
482 count++;
483 }
484
485 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
486 rp = kmalloc(rp_len, GFP_ATOMIC);
487 if (!rp) {
488 read_unlock(&hci_dev_list_lock);
489 return -ENOMEM;
490 }
491
492 count = 0;
493 list_for_each_entry(d, &hci_dev_list, list) {
494 if (hci_dev_test_flag(d, HCI_SETUP) ||
495 hci_dev_test_flag(d, HCI_CONFIG) ||
496 hci_dev_test_flag(d, HCI_USER_CHANNEL))
497 continue;
498
499 /* Devices marked as raw-only are neither configured
500 * nor unconfigured controllers.
501 */
502 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
503 continue;
504
505 if (d->dev_type == HCI_BREDR) {
506 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
507 rp->entry[count].type = 0x01;
508 else
509 rp->entry[count].type = 0x00;
510 } else if (d->dev_type == HCI_AMP) {
511 rp->entry[count].type = 0x02;
512 } else {
513 continue;
514 }
515
516 rp->entry[count].bus = d->bus;
517 rp->entry[count++].index = cpu_to_le16(d->id);
518 BT_DBG("Added hci%u", d->id);
519 }
520
521 rp->num_controllers = cpu_to_le16(count);
522 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
523
524 read_unlock(&hci_dev_list_lock);
525
526 /* If this command is called at least once, then all the
527 * default index and unconfigured index events are disabled
528 * and from now on only extended index events are used.
529 */
530 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
531 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
532 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
533
534 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
535 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
536
537 kfree(rp);
538
539 return err;
540}
541
Marcel Holtmanndbece372014-07-04 18:11:55 +0200542static bool is_configured(struct hci_dev *hdev)
543{
544 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700545 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200546 return false;
547
548 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
549 !bacmp(&hdev->public_addr, BDADDR_ANY))
550 return false;
551
552 return true;
553}
554
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200555static __le32 get_missing_options(struct hci_dev *hdev)
556{
557 u32 options = 0;
558
Marcel Holtmanndbece372014-07-04 18:11:55 +0200559 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700560 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200561 options |= MGMT_OPTION_EXTERNAL_CONFIG;
562
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200563 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
564 !bacmp(&hdev->public_addr, BDADDR_ANY))
565 options |= MGMT_OPTION_PUBLIC_ADDRESS;
566
567 return cpu_to_le32(options);
568}
569
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200570static int new_options(struct hci_dev *hdev, struct sock *skip)
571{
572 __le32 options = get_missing_options(hdev);
573
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700574 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
575 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576}
577
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
579{
580 __le32 options = get_missing_options(hdev);
581
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200582 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
583 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584}
585
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200586static int read_config_info(struct sock *sk, struct hci_dev *hdev,
587 void *data, u16 data_len)
588{
589 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200590 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591
592 BT_DBG("sock %p %s", sk, hdev->name);
593
594 hci_dev_lock(hdev);
595
596 memset(&rp, 0, sizeof(rp));
597 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
600 options |= MGMT_OPTION_EXTERNAL_CONFIG;
601
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200602 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603 options |= MGMT_OPTION_PUBLIC_ADDRESS;
604
605 rp.supported_options = cpu_to_le32(options);
606 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607
608 hci_dev_unlock(hdev);
609
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
611 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612}
613
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200614static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200615{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200617
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300619 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800620 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300621 settings |= MGMT_SETTING_CONNECTABLE;
622 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Andre Guedesed3fa312012-07-24 15:03:46 -0300624 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500625 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
626 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627 settings |= MGMT_SETTING_BREDR;
628 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700629
630 if (lmp_ssp_capable(hdev)) {
631 settings |= MGMT_SETTING_SSP;
632 settings |= MGMT_SETTING_HS;
633 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800634
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800635 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800636 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700637 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100638
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300639 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200640 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300641 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300642 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200643 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800644 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300645 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200646
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200647 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
648 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200649 settings |= MGMT_SETTING_CONFIGURATION;
650
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651 return settings;
652}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200653
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200654static u32 get_current_settings(struct hci_dev *hdev)
655{
656 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200657
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200658 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100659 settings |= MGMT_SETTING_POWERED;
660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662 settings |= MGMT_SETTING_CONNECTABLE;
663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700664 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500665 settings |= MGMT_SETTING_FAST_CONNECTABLE;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_DISCOVERABLE;
669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300671 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_BREDR;
675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200683 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200686 settings |= MGMT_SETTING_HS;
687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300689 settings |= MGMT_SETTING_ADVERTISING;
690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700691 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800692 settings |= MGMT_SETTING_SECURE_CONN;
693
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700694 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800695 settings |= MGMT_SETTING_DEBUG_KEYS;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200698 settings |= MGMT_SETTING_PRIVACY;
699
Marcel Holtmann93690c22015-03-06 10:11:21 -0800700 /* The current setting for static address has two purposes. The
701 * first is to indicate if the static address will be used and
702 * the second is to indicate if it is actually set.
703 *
704 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700705 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800706 * address is actually used decides if the flag is set or not.
707 *
708 * For single mode LE only controllers and dual-mode controllers
709 * with BR/EDR disabled, the existence of the static address will
710 * be evaluated.
711 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700712 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700713 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800714 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
715 if (bacmp(&hdev->static_addr, BDADDR_ANY))
716 settings |= MGMT_SETTING_STATIC_ADDRESS;
717 }
718
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200720}
721
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300722#define PNP_INFO_SVCLASS_ID 0x1200
723
Johan Hedberg213202e2013-01-27 00:31:33 +0200724static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
725{
726 u8 *ptr = data, *uuids_start = NULL;
727 struct bt_uuid *uuid;
728
729 if (len < 4)
730 return ptr;
731
732 list_for_each_entry(uuid, &hdev->uuids, list) {
733 u16 uuid16;
734
735 if (uuid->size != 16)
736 continue;
737
738 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
739 if (uuid16 < 0x1100)
740 continue;
741
742 if (uuid16 == PNP_INFO_SVCLASS_ID)
743 continue;
744
745 if (!uuids_start) {
746 uuids_start = ptr;
747 uuids_start[0] = 1;
748 uuids_start[1] = EIR_UUID16_ALL;
749 ptr += 2;
750 }
751
752 /* Stop if not enough space to put next UUID */
753 if ((ptr - data) + sizeof(u16) > len) {
754 uuids_start[1] = EIR_UUID16_SOME;
755 break;
756 }
757
758 *ptr++ = (uuid16 & 0x00ff);
759 *ptr++ = (uuid16 & 0xff00) >> 8;
760 uuids_start[0] += sizeof(uuid16);
761 }
762
763 return ptr;
764}
765
Johan Hedbergcdf19632013-01-27 00:31:34 +0200766static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
767{
768 u8 *ptr = data, *uuids_start = NULL;
769 struct bt_uuid *uuid;
770
771 if (len < 6)
772 return ptr;
773
774 list_for_each_entry(uuid, &hdev->uuids, list) {
775 if (uuid->size != 32)
776 continue;
777
778 if (!uuids_start) {
779 uuids_start = ptr;
780 uuids_start[0] = 1;
781 uuids_start[1] = EIR_UUID32_ALL;
782 ptr += 2;
783 }
784
785 /* Stop if not enough space to put next UUID */
786 if ((ptr - data) + sizeof(u32) > len) {
787 uuids_start[1] = EIR_UUID32_SOME;
788 break;
789 }
790
791 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
792 ptr += sizeof(u32);
793 uuids_start[0] += sizeof(u32);
794 }
795
796 return ptr;
797}
798
Johan Hedbergc00d5752013-01-27 00:31:35 +0200799static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
800{
801 u8 *ptr = data, *uuids_start = NULL;
802 struct bt_uuid *uuid;
803
804 if (len < 18)
805 return ptr;
806
807 list_for_each_entry(uuid, &hdev->uuids, list) {
808 if (uuid->size != 128)
809 continue;
810
811 if (!uuids_start) {
812 uuids_start = ptr;
813 uuids_start[0] = 1;
814 uuids_start[1] = EIR_UUID128_ALL;
815 ptr += 2;
816 }
817
818 /* Stop if not enough space to put next UUID */
819 if ((ptr - data) + 16 > len) {
820 uuids_start[1] = EIR_UUID128_SOME;
821 break;
822 }
823
824 memcpy(ptr, uuid->uuid, 16);
825 ptr += 16;
826 uuids_start[0] += 16;
827 }
828
829 return ptr;
830}
831
Johan Hedberg333ae952015-03-17 13:48:47 +0200832static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
833{
834 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
835}
836
Johan Hedberg333ae952015-03-17 13:48:47 +0200837static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
838 struct hci_dev *hdev,
839 const void *data)
840{
841 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
842}
843
Johan Hedbergf2252572015-11-18 12:49:20 +0200844u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300845{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200846 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300847
848 /* If there's a pending mgmt command the flags will not yet have
849 * their final values, so check for this first.
850 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200851 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300852 if (cmd) {
853 struct mgmt_mode *cp = cmd->param;
854 if (cp->val == 0x01)
855 return LE_AD_GENERAL;
856 else if (cp->val == 0x02)
857 return LE_AD_LIMITED;
858 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700859 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300860 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700861 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300862 return LE_AD_GENERAL;
863 }
864
865 return 0;
866}
867
Johan Hedbergf2252572015-11-18 12:49:20 +0200868bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700869{
870 struct mgmt_pending_cmd *cmd;
871
872 /* If there's a pending mgmt command the flag will not yet have
873 * it's final value, so check for this first.
874 */
875 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
876 if (cmd) {
877 struct mgmt_mode *cp = cmd->param;
878
879 return cp->val;
880 }
881
882 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
883}
884
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300885static void create_eir(struct hci_dev *hdev, u8 *data)
886{
887 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300888 size_t name_len;
889
890 name_len = strlen(hdev->dev_name);
891
892 if (name_len > 0) {
893 /* EIR Data type */
894 if (name_len > 48) {
895 name_len = 48;
896 ptr[1] = EIR_NAME_SHORT;
897 } else
898 ptr[1] = EIR_NAME_COMPLETE;
899
900 /* EIR Data length */
901 ptr[0] = name_len + 1;
902
903 memcpy(ptr + 2, hdev->dev_name, name_len);
904
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300905 ptr += (name_len + 2);
906 }
907
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100908 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700909 ptr[0] = 2;
910 ptr[1] = EIR_TX_POWER;
911 ptr[2] = (u8) hdev->inq_tx_power;
912
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700913 ptr += 3;
914 }
915
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700916 if (hdev->devid_source > 0) {
917 ptr[0] = 9;
918 ptr[1] = EIR_DEVICE_ID;
919
920 put_unaligned_le16(hdev->devid_source, ptr + 2);
921 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
922 put_unaligned_le16(hdev->devid_product, ptr + 6);
923 put_unaligned_le16(hdev->devid_version, ptr + 8);
924
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700925 ptr += 10;
926 }
927
Johan Hedberg213202e2013-01-27 00:31:33 +0200928 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200929 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200930 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300931}
932
Johan Hedberg890ea892013-03-15 17:06:52 -0500933static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300934{
Johan Hedberg890ea892013-03-15 17:06:52 -0500935 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300936 struct hci_cp_write_eir cp;
937
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200938 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500939 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200940
Johan Hedberg976eb202012-10-24 21:12:01 +0300941 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500942 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300943
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700944 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -0500945 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300946
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700947 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -0500948 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300949
950 memset(&cp, 0, sizeof(cp));
951
952 create_eir(hdev, cp.data);
953
954 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500955 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300956
957 memcpy(hdev->eir, cp.data, sizeof(cp.data));
958
Johan Hedberg890ea892013-03-15 17:06:52 -0500959 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300960}
961
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200962static u8 get_service_classes(struct hci_dev *hdev)
963{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300964 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200965 u8 val = 0;
966
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300967 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200968 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200969
970 return val;
971}
972
Johan Hedberg890ea892013-03-15 17:06:52 -0500973static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200974{
Johan Hedberg890ea892013-03-15 17:06:52 -0500975 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200976 u8 cod[3];
977
978 BT_DBG("%s", hdev->name);
979
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200980 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500981 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200982
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700983 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300984 return;
985
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700986 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -0500987 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200988
989 cod[0] = hdev->minor_class;
990 cod[1] = hdev->major_class;
991 cod[2] = get_service_classes(hdev);
992
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700993 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700994 cod[1] |= 0x20;
995
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500997 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998
Johan Hedberg890ea892013-03-15 17:06:52 -0500999 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001000}
1001
Johan Hedberg7d785252011-12-15 00:47:39 +02001002static void service_cache_off(struct work_struct *work)
1003{
1004 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001005 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001006 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001007
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001008 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001009 return;
1010
Johan Hedberg890ea892013-03-15 17:06:52 -05001011 hci_req_init(&req, hdev);
1012
Johan Hedberg7d785252011-12-15 00:47:39 +02001013 hci_dev_lock(hdev);
1014
Johan Hedberg890ea892013-03-15 17:06:52 -05001015 update_eir(&req);
1016 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001017
1018 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001019
1020 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001021}
1022
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001023static void rpa_expired(struct work_struct *work)
1024{
1025 struct hci_dev *hdev = container_of(work, struct hci_dev,
1026 rpa_expired.work);
1027 struct hci_request req;
1028
1029 BT_DBG("");
1030
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001031 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001032
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001033 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001034 return;
1035
1036 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +02001037 * controller happens in the hci_req_enable_advertising()
1038 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001039 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001040 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001041 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001042 hci_req_run(&req, NULL);
1043}
1044
Johan Hedberg6a919082012-02-28 06:17:26 +02001045static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001046{
Marcel Holtmann238be782015-03-13 02:11:06 -07001047 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001048 return;
1049
Johan Hedberg4f87da82012-03-02 19:55:56 +02001050 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001051 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001052
Johan Hedberg4f87da82012-03-02 19:55:56 +02001053 /* Non-mgmt controlled devices get this bit set
1054 * implicitly so that pairing works for them, however
1055 * for mgmt we require user-space to explicitly enable
1056 * it
1057 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001058 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001059}
1060
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001061static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001062 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001063{
1064 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001065
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001066 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001067
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001068 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001069
Johan Hedberg03811012010-12-08 00:21:06 +02001070 memset(&rp, 0, sizeof(rp));
1071
Johan Hedberg03811012010-12-08 00:21:06 +02001072 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001073
1074 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001075 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001076
1077 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1078 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1079
1080 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001081
1082 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001083 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001084
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001085 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001086
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001087 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1088 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001089}
1090
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001091static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001092{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001093 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001094
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001095 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1096 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001097}
1098
Marcel Holtmann1904a852015-01-11 13:50:44 -08001099static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001100{
1101 BT_DBG("%s status 0x%02x", hdev->name, status);
1102
Johan Hedberga3172b72014-02-28 09:33:44 +02001103 if (hci_conn_count(hdev) == 0) {
1104 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001105 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001106 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001107}
1108
Johan Hedbergf2252572015-11-18 12:49:20 +02001109void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001110{
1111 struct mgmt_ev_advertising_added ev;
1112
1113 ev.instance = instance;
1114
1115 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1116}
1117
Johan Hedbergf2252572015-11-18 12:49:20 +02001118void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1119 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001120{
1121 struct mgmt_ev_advertising_removed ev;
1122
1123 ev.instance = instance;
1124
1125 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1126}
1127
Florian Grandel7816b822015-06-18 03:16:45 +02001128static void cancel_adv_timeout(struct hci_dev *hdev)
1129{
1130 if (hdev->adv_instance_timeout) {
1131 hdev->adv_instance_timeout = 0;
1132 cancel_delayed_work(&hdev->adv_instance_expire);
1133 }
1134}
1135
Johan Hedberg8b064a32014-02-24 14:52:22 +02001136static int clean_up_hci_state(struct hci_dev *hdev)
1137{
1138 struct hci_request req;
1139 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001140 bool discov_stopped;
1141 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001142
1143 hci_req_init(&req, hdev);
1144
1145 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1146 test_bit(HCI_PSCAN, &hdev->flags)) {
1147 u8 scan = 0x00;
1148 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1149 }
1150
Johan Hedbergf2252572015-11-18 12:49:20 +02001151 hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001152
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001153 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001154 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001155
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001156 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001157
1158 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001159 /* 0x15 == Terminated due to Power Off */
1160 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001161 }
1162
Johan Hedberg23a48092014-07-08 16:05:06 +03001163 err = hci_req_run(&req, clean_up_hci_complete);
1164 if (!err && discov_stopped)
1165 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1166
1167 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001168}
1169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001170static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001171 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001172{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001173 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001174 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001175 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001177 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001178
Johan Hedberga7e80f22013-01-09 16:05:19 +02001179 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001180 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1181 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001182
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001183 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001184
Johan Hedberg333ae952015-03-17 13:48:47 +02001185 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001186 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1187 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001188 goto failed;
1189 }
1190
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001191 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001192 cancel_delayed_work(&hdev->power_off);
1193
1194 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001195 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1196 data, len);
1197 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001198 goto failed;
1199 }
1200 }
1201
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001202 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001203 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001204 goto failed;
1205 }
1206
Johan Hedberg03811012010-12-08 00:21:06 +02001207 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1208 if (!cmd) {
1209 err = -ENOMEM;
1210 goto failed;
1211 }
1212
Johan Hedberg8b064a32014-02-24 14:52:22 +02001213 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001214 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001215 err = 0;
1216 } else {
1217 /* Disconnect connections, stop scans, etc */
1218 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001219 if (!err)
1220 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1221 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001222
Johan Hedberg8b064a32014-02-24 14:52:22 +02001223 /* ENODATA means there were no HCI commands queued */
1224 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001225 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001226 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1227 err = 0;
1228 }
1229 }
Johan Hedberg03811012010-12-08 00:21:06 +02001230
1231failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001232 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001233 return err;
1234}
1235
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001236static int new_settings(struct hci_dev *hdev, struct sock *skip)
1237{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001238 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001239
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001240 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1241 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001242}
1243
Johan Hedberg91a668b2014-07-09 13:28:26 +03001244int mgmt_new_settings(struct hci_dev *hdev)
1245{
1246 return new_settings(hdev, NULL);
1247}
1248
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001249struct cmd_lookup {
1250 struct sock *sk;
1251 struct hci_dev *hdev;
1252 u8 mgmt_status;
1253};
1254
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001255static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001256{
1257 struct cmd_lookup *match = data;
1258
1259 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1260
1261 list_del(&cmd->list);
1262
1263 if (match->sk == NULL) {
1264 match->sk = cmd->sk;
1265 sock_hold(match->sk);
1266 }
1267
1268 mgmt_pending_free(cmd);
1269}
1270
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001271static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001272{
1273 u8 *status = data;
1274
Johan Hedberga69e8372015-03-06 21:08:53 +02001275 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001276 mgmt_pending_remove(cmd);
1277}
1278
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001279static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001280{
1281 if (cmd->cmd_complete) {
1282 u8 *status = data;
1283
1284 cmd->cmd_complete(cmd, *status);
1285 mgmt_pending_remove(cmd);
1286
1287 return;
1288 }
1289
1290 cmd_status_rsp(cmd, data);
1291}
1292
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001293static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001294{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001295 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1296 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001297}
1298
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001299static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001300{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001301 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1302 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001303}
1304
Johan Hedberge6fe7982013-10-02 15:45:22 +03001305static u8 mgmt_bredr_support(struct hci_dev *hdev)
1306{
1307 if (!lmp_bredr_capable(hdev))
1308 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001309 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001310 return MGMT_STATUS_REJECTED;
1311 else
1312 return MGMT_STATUS_SUCCESS;
1313}
1314
1315static u8 mgmt_le_support(struct hci_dev *hdev)
1316{
1317 if (!lmp_le_capable(hdev))
1318 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001319 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001320 return MGMT_STATUS_REJECTED;
1321 else
1322 return MGMT_STATUS_SUCCESS;
1323}
1324
Marcel Holtmann1904a852015-01-11 13:50:44 -08001325static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1326 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001327{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001328 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001329 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001330 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001331 bool changed;
1332
1333 BT_DBG("status 0x%02x", status);
1334
1335 hci_dev_lock(hdev);
1336
Johan Hedberg333ae952015-03-17 13:48:47 +02001337 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001338 if (!cmd)
1339 goto unlock;
1340
1341 if (status) {
1342 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001343 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001344 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001345 goto remove_cmd;
1346 }
1347
1348 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001349 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001350 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001351
1352 if (hdev->discov_timeout > 0) {
1353 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1354 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1355 to);
1356 }
1357 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001358 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001359 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001360
1361 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1362
1363 if (changed)
1364 new_settings(hdev, cmd->sk);
1365
Marcel Holtmann970ba522013-10-15 06:33:57 -07001366 /* When the discoverable mode gets changed, make sure
1367 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001368 * bit correctly set. Also update page scan based on whitelist
1369 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001370 */
1371 hci_req_init(&req, hdev);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001372 __hci_req_update_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001373 update_class(&req);
1374 hci_req_run(&req, NULL);
1375
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001376remove_cmd:
1377 mgmt_pending_remove(cmd);
1378
1379unlock:
1380 hci_dev_unlock(hdev);
1381}
1382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001383static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001384 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001385{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001386 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001387 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001388 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001389 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001390 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001391 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001394
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001395 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1396 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001397 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1398 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001399
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001400 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001401 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1402 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001403
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001404 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001405
1406 /* Disabling discoverable requires that no timeout is set,
1407 * and enabling limited discoverable requires a timeout.
1408 */
1409 if ((cp->val == 0x00 && timeout > 0) ||
1410 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001411 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1412 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001413
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001414 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001415
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001416 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001417 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1418 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001419 goto failed;
1420 }
1421
Johan Hedberg333ae952015-03-17 13:48:47 +02001422 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1423 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001424 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1425 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001426 goto failed;
1427 }
1428
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001429 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001430 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1431 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001432 goto failed;
1433 }
1434
1435 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001436 bool changed = false;
1437
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001438 /* Setting limited discoverable when powered off is
1439 * not a valid operation since it requires a timeout
1440 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1441 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001442 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001443 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001444 changed = true;
1445 }
1446
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001447 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001448 if (err < 0)
1449 goto failed;
1450
1451 if (changed)
1452 err = new_settings(hdev, sk);
1453
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001454 goto failed;
1455 }
1456
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001457 /* If the current mode is the same, then just update the timeout
1458 * value with the new value. And if only the timeout gets updated,
1459 * then no need for any HCI transactions.
1460 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001461 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1462 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1463 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001464 cancel_delayed_work(&hdev->discov_off);
1465 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001466
Marcel Holtmann36261542013-10-15 08:28:51 -07001467 if (cp->val && hdev->discov_timeout > 0) {
1468 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001469 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001470 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001471 }
1472
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001473 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001474 goto failed;
1475 }
1476
1477 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1478 if (!cmd) {
1479 err = -ENOMEM;
1480 goto failed;
1481 }
1482
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001483 /* Cancel any potential discoverable timeout that might be
1484 * still active and store new timeout value. The arming of
1485 * the timeout happens in the complete handler.
1486 */
1487 cancel_delayed_work(&hdev->discov_off);
1488 hdev->discov_timeout = timeout;
1489
Johan Hedbergb456f872013-10-19 23:38:22 +03001490 /* Limited discoverable mode */
1491 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001492 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001493 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001494 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001495
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001496 hci_req_init(&req, hdev);
1497
Johan Hedberg9a43e252013-10-20 19:00:07 +03001498 /* The procedure for LE-only controllers is much simpler - just
1499 * update the advertising data.
1500 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001501 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001502 goto update_ad;
1503
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001504 scan = SCAN_PAGE;
1505
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001506 if (cp->val) {
1507 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001508
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001509 if (cp->val == 0x02) {
1510 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001511 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001512 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1513 hci_cp.iac_lap[1] = 0x8b;
1514 hci_cp.iac_lap[2] = 0x9e;
1515 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1516 hci_cp.iac_lap[4] = 0x8b;
1517 hci_cp.iac_lap[5] = 0x9e;
1518 } else {
1519 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001520 hci_cp.num_iac = 1;
1521 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1522 hci_cp.iac_lap[1] = 0x8b;
1523 hci_cp.iac_lap[2] = 0x9e;
1524 }
1525
1526 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1527 (hci_cp.num_iac * 3) + 1, &hci_cp);
1528
1529 scan |= SCAN_INQUIRY;
1530 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001531 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001532 }
1533
1534 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001535
Johan Hedberg9a43e252013-10-20 19:00:07 +03001536update_ad:
Johan Hedbergf2252572015-11-18 12:49:20 +02001537 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedberg9a43e252013-10-20 19:00:07 +03001538
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001539 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001540 if (err < 0)
1541 mgmt_pending_remove(cmd);
1542
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001543failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001544 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001545 return err;
1546}
1547
Johan Hedberg406d7802013-03-15 17:07:09 -05001548static void write_fast_connectable(struct hci_request *req, bool enable)
1549{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001550 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001551 struct hci_cp_write_page_scan_activity acp;
1552 u8 type;
1553
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001554 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001555 return;
1556
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001557 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1558 return;
1559
Johan Hedberg406d7802013-03-15 17:07:09 -05001560 if (enable) {
1561 type = PAGE_SCAN_TYPE_INTERLACED;
1562
1563 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001564 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001565 } else {
1566 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1567
1568 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001569 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001570 }
1571
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001572 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001573
Johan Hedbergbd98b992013-03-15 17:07:13 -05001574 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1575 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1576 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1577 sizeof(acp), &acp);
1578
1579 if (hdev->page_scan_type != type)
1580 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001581}
1582
Marcel Holtmann1904a852015-01-11 13:50:44 -08001583static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1584 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001585{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001586 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001587 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001588 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001589
1590 BT_DBG("status 0x%02x", status);
1591
1592 hci_dev_lock(hdev);
1593
Johan Hedberg333ae952015-03-17 13:48:47 +02001594 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001595 if (!cmd)
1596 goto unlock;
1597
Johan Hedberg37438c12013-10-14 16:20:05 +03001598 if (status) {
1599 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001600 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001601 goto remove_cmd;
1602 }
1603
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001604 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001605 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001606 conn_changed = !hci_dev_test_and_set_flag(hdev,
1607 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001608 discov_changed = false;
1609 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001610 conn_changed = hci_dev_test_and_clear_flag(hdev,
1611 HCI_CONNECTABLE);
1612 discov_changed = hci_dev_test_and_clear_flag(hdev,
1613 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001614 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001615
Johan Hedberg2b76f452013-03-15 17:07:04 -05001616 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1617
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001618 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001619 new_settings(hdev, cmd->sk);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001620 hci_req_update_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001621 if (discov_changed)
Johan Hedbergf2252572015-11-18 12:49:20 +02001622 hci_req_update_adv_data(hdev, HCI_ADV_CURRENT);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001623 hci_update_background_scan(hdev);
1624 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001625
Johan Hedberg37438c12013-10-14 16:20:05 +03001626remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001627 mgmt_pending_remove(cmd);
1628
1629unlock:
1630 hci_dev_unlock(hdev);
1631}
1632
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001633static int set_connectable_update_settings(struct hci_dev *hdev,
1634 struct sock *sk, u8 val)
1635{
1636 bool changed = false;
1637 int err;
1638
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001639 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001640 changed = true;
1641
1642 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001643 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001644 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001645 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1646 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001647 }
1648
1649 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1650 if (err < 0)
1651 return err;
1652
Johan Hedberg562064e2014-07-08 16:35:34 +03001653 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001654 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001655 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001656 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001657 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001658
1659 return 0;
1660}
1661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001662static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001663 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001664{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001665 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001666 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001667 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001668 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001669 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001671 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001673 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1674 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001675 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1676 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001677
Johan Hedberga7e80f22013-01-09 16:05:19 +02001678 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001679 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1680 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001681
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001682 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001683
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001684 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001685 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001686 goto failed;
1687 }
1688
Johan Hedberg333ae952015-03-17 13:48:47 +02001689 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1690 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001691 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1692 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001693 goto failed;
1694 }
1695
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001696 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1697 if (!cmd) {
1698 err = -ENOMEM;
1699 goto failed;
1700 }
1701
Johan Hedberg2b76f452013-03-15 17:07:04 -05001702 hci_req_init(&req, hdev);
1703
Johan Hedberg9a43e252013-10-20 19:00:07 +03001704 /* If BR/EDR is not enabled and we disable advertising as a
1705 * by-product of disabling connectable, we need to update the
1706 * advertising flags.
1707 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001708 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03001709 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001710 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1711 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03001712 }
Johan Hedbergf2252572015-11-18 12:49:20 +02001713 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedberg9a43e252013-10-20 19:00:07 +03001714 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001715 if (cp->val) {
1716 scan = SCAN_PAGE;
1717 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03001718 /* If we don't have any whitelist entries just
1719 * disable all scanning. If there are entries
1720 * and we had both page and inquiry scanning
1721 * enabled then fall back to only page scanning.
1722 * Otherwise no changes are needed.
1723 */
1724 if (list_empty(&hdev->whitelist))
1725 scan = SCAN_DISABLED;
1726 else if (test_bit(HCI_ISCAN, &hdev->flags))
1727 scan = SCAN_PAGE;
1728 else
1729 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03001730
1731 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001732 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001733 cancel_delayed_work(&hdev->discov_off);
1734 }
1735
1736 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1737 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001738
Johan Hedberg3bd27242014-07-28 20:53:58 +03001739no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03001740 /* Update the advertising parameters if necessary */
Arman Uguray880897d2015-03-28 12:39:00 -07001741 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
1742 hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
Johan Hedbergf2252572015-11-18 12:49:20 +02001743 __hci_req_enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001744
Johan Hedberg2b76f452013-03-15 17:07:04 -05001745 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001746 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001747 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001748 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001749 err = set_connectable_update_settings(hdev, sk,
1750 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001751 goto failed;
1752 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001753
1754failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001755 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001756 return err;
1757}
1758
Johan Hedbergb2939472014-07-30 09:22:23 +03001759static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001760 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001761{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001762 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001763 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001764 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001765
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001766 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001767
Johan Hedberga7e80f22013-01-09 16:05:19 +02001768 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001769 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1770 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001772 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001773
1774 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001775 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001776 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001777 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001778
Johan Hedbergb2939472014-07-30 09:22:23 +03001779 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001780 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001781 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001782
Marcel Holtmann55594352013-10-06 16:11:57 -07001783 if (changed)
1784 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001785
Marcel Holtmann55594352013-10-06 16:11:57 -07001786unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001787 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001788 return err;
1789}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001790
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001791static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1792 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001793{
1794 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001795 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001796 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001797 int err;
1798
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001799 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001800
Johan Hedberge6fe7982013-10-02 15:45:22 +03001801 status = mgmt_bredr_support(hdev);
1802 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001803 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1804 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001805
Johan Hedberga7e80f22013-01-09 16:05:19 +02001806 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001807 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1808 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001809
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001810 hci_dev_lock(hdev);
1811
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001812 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001813 bool changed = false;
1814
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001815 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001816 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001817 changed = true;
1818 }
1819
1820 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1821 if (err < 0)
1822 goto failed;
1823
1824 if (changed)
1825 err = new_settings(hdev, sk);
1826
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001827 goto failed;
1828 }
1829
Johan Hedberg333ae952015-03-17 13:48:47 +02001830 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001831 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1832 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001833 goto failed;
1834 }
1835
1836 val = !!cp->val;
1837
1838 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1839 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1840 goto failed;
1841 }
1842
1843 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1844 if (!cmd) {
1845 err = -ENOMEM;
1846 goto failed;
1847 }
1848
1849 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1850 if (err < 0) {
1851 mgmt_pending_remove(cmd);
1852 goto failed;
1853 }
1854
1855failed:
1856 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001857 return err;
1858}
1859
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001860static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001861{
1862 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001863 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001864 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001865 int err;
1866
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001867 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001868
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001869 status = mgmt_bredr_support(hdev);
1870 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001871 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001872
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001873 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001874 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1875 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001876
Johan Hedberga7e80f22013-01-09 16:05:19 +02001877 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001878 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1879 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001880
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001881 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001882
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001883 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001884 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001885
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001886 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001887 changed = !hci_dev_test_and_set_flag(hdev,
1888 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001889 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001890 changed = hci_dev_test_and_clear_flag(hdev,
1891 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001892 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001893 changed = hci_dev_test_and_clear_flag(hdev,
1894 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001895 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001896 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001897 }
1898
1899 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1900 if (err < 0)
1901 goto failed;
1902
1903 if (changed)
1904 err = new_settings(hdev, sk);
1905
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001906 goto failed;
1907 }
1908
Johan Hedberg333ae952015-03-17 13:48:47 +02001909 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001910 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1911 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001912 goto failed;
1913 }
1914
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001915 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001916 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1917 goto failed;
1918 }
1919
1920 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1921 if (!cmd) {
1922 err = -ENOMEM;
1923 goto failed;
1924 }
1925
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001926 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001927 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1928 sizeof(cp->val), &cp->val);
1929
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001930 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001931 if (err < 0) {
1932 mgmt_pending_remove(cmd);
1933 goto failed;
1934 }
1935
1936failed:
1937 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001938 return err;
1939}
1940
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001941static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001942{
1943 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001944 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001945 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001946 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001947
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001948 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001949
Johan Hedberge6fe7982013-10-02 15:45:22 +03001950 status = mgmt_bredr_support(hdev);
1951 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001952 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001953
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001954 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001955 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1956 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001957
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001958 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001959 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1960 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001961
Johan Hedberga7e80f22013-01-09 16:05:19 +02001962 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001963 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1964 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001965
Marcel Holtmannee392692013-10-01 22:59:23 -07001966 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001967
Johan Hedberg333ae952015-03-17 13:48:47 +02001968 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001969 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1970 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001971 goto unlock;
1972 }
1973
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001974 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001975 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001976 } else {
1977 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001978 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1979 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001980 goto unlock;
1981 }
1982
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001983 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001984 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001985
1986 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1987 if (err < 0)
1988 goto unlock;
1989
1990 if (changed)
1991 err = new_settings(hdev, sk);
1992
1993unlock:
1994 hci_dev_unlock(hdev);
1995 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001996}
1997
Marcel Holtmann1904a852015-01-11 13:50:44 -08001998static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001999{
2000 struct cmd_lookup match = { NULL, hdev };
2001
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302002 hci_dev_lock(hdev);
2003
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002004 if (status) {
2005 u8 mgmt_err = mgmt_status(status);
2006
2007 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2008 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302009 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002010 }
2011
2012 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2013
2014 new_settings(hdev, match.sk);
2015
2016 if (match.sk)
2017 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002018
2019 /* Make sure the controller has a good default for
2020 * advertising data. Restrict the update to when LE
2021 * has actually been enabled. During power on, the
2022 * update in powered_update_hci will take care of it.
2023 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002024 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002025 struct hci_request req;
2026
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002027 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02002028 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
2029 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002030 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02002031 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002032 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302033
2034unlock:
2035 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002036}
2037
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002038static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002039{
2040 struct mgmt_mode *cp = data;
2041 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002042 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002043 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002044 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002045 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002047 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002048
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002049 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002050 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2051 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002052
Johan Hedberga7e80f22013-01-09 16:05:19 +02002053 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002054 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2055 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002056
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002057 /* Bluetooth single mode LE only controllers or dual-mode
2058 * controllers configured as LE only devices, do not allow
2059 * switching LE off. These have either LE enabled explicitly
2060 * or BR/EDR has been previously switched off.
2061 *
2062 * When trying to enable an already enabled LE, then gracefully
2063 * send a positive response. Trying to disable it however will
2064 * result into rejection.
2065 */
2066 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
2067 if (cp->val == 0x01)
2068 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2069
Johan Hedberga69e8372015-03-06 21:08:53 +02002070 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2071 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002072 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03002073
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002074 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002075
2076 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002077 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002078
Florian Grandel847818d2015-06-18 03:16:46 +02002079 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02002080 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02002081
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002082 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002083 bool changed = false;
2084
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002085 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002086 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002087 changed = true;
2088 }
2089
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002090 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002091 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002092 changed = true;
2093 }
2094
Johan Hedberg06199cf2012-02-22 16:37:11 +02002095 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2096 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002097 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002098
2099 if (changed)
2100 err = new_settings(hdev, sk);
2101
Johan Hedberg1de028c2012-02-29 19:55:35 -08002102 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002103 }
2104
Johan Hedberg333ae952015-03-17 13:48:47 +02002105 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2106 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002107 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2108 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002109 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002110 }
2111
2112 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2113 if (!cmd) {
2114 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002115 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002116 }
2117
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002118 hci_req_init(&req, hdev);
2119
Johan Hedberg06199cf2012-02-22 16:37:11 +02002120 memset(&hci_cp, 0, sizeof(hci_cp));
2121
2122 if (val) {
2123 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002124 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002125 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002126 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02002127 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002128 }
2129
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002130 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2131 &hci_cp);
2132
2133 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302134 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002135 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002136
Johan Hedberg1de028c2012-02-29 19:55:35 -08002137unlock:
2138 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002139 return err;
2140}
2141
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002142/* This is a helper function to test for pending mgmt commands that can
2143 * cause CoD or EIR HCI commands. We can only allow one such pending
2144 * mgmt command at a time since otherwise we cannot easily track what
2145 * the current values are, will be, and based on that calculate if a new
2146 * HCI command needs to be sent and if yes with what value.
2147 */
2148static bool pending_eir_or_class(struct hci_dev *hdev)
2149{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002150 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002151
2152 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2153 switch (cmd->opcode) {
2154 case MGMT_OP_ADD_UUID:
2155 case MGMT_OP_REMOVE_UUID:
2156 case MGMT_OP_SET_DEV_CLASS:
2157 case MGMT_OP_SET_POWERED:
2158 return true;
2159 }
2160 }
2161
2162 return false;
2163}
2164
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002165static const u8 bluetooth_base_uuid[] = {
2166 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2167 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2168};
2169
2170static u8 get_uuid_size(const u8 *uuid)
2171{
2172 u32 val;
2173
2174 if (memcmp(uuid, bluetooth_base_uuid, 12))
2175 return 128;
2176
2177 val = get_unaligned_le32(&uuid[12]);
2178 if (val > 0xffff)
2179 return 32;
2180
2181 return 16;
2182}
2183
Johan Hedberg92da6092013-03-15 17:06:55 -05002184static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2185{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002186 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002187
2188 hci_dev_lock(hdev);
2189
Johan Hedberg333ae952015-03-17 13:48:47 +02002190 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002191 if (!cmd)
2192 goto unlock;
2193
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002194 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2195 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002196
2197 mgmt_pending_remove(cmd);
2198
2199unlock:
2200 hci_dev_unlock(hdev);
2201}
2202
Marcel Holtmann1904a852015-01-11 13:50:44 -08002203static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002204{
2205 BT_DBG("status 0x%02x", status);
2206
2207 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2208}
2209
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002213 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002214 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002215 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002216 int err;
2217
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002218 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002219
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002220 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002221
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002222 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002223 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2224 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002225 goto failed;
2226 }
2227
Andre Guedes92c4c202012-06-07 19:05:44 -03002228 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002229 if (!uuid) {
2230 err = -ENOMEM;
2231 goto failed;
2232 }
2233
2234 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002235 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002236 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002237
Johan Hedbergde66aa62013-01-27 00:31:27 +02002238 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002239
Johan Hedberg890ea892013-03-15 17:06:52 -05002240 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002241
Johan Hedberg890ea892013-03-15 17:06:52 -05002242 update_class(&req);
2243 update_eir(&req);
2244
Johan Hedberg92da6092013-03-15 17:06:55 -05002245 err = hci_req_run(&req, add_uuid_complete);
2246 if (err < 0) {
2247 if (err != -ENODATA)
2248 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002249
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002250 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2251 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002252 goto failed;
2253 }
2254
2255 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002256 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002257 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002258 goto failed;
2259 }
2260
2261 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002262
2263failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002264 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002265 return err;
2266}
2267
Johan Hedberg24b78d02012-02-23 23:24:30 +02002268static bool enable_service_cache(struct hci_dev *hdev)
2269{
2270 if (!hdev_is_powered(hdev))
2271 return false;
2272
Marcel Holtmann238be782015-03-13 02:11:06 -07002273 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002274 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2275 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002276 return true;
2277 }
2278
2279 return false;
2280}
2281
Marcel Holtmann1904a852015-01-11 13:50:44 -08002282static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002283{
2284 BT_DBG("status 0x%02x", status);
2285
2286 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2287}
2288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002290 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002291{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002292 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002293 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002294 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002295 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 -05002296 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002297 int err, found;
2298
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002300
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002301 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002302
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002303 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002304 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2305 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002306 goto unlock;
2307 }
2308
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002309 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002310 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002311
Johan Hedberg24b78d02012-02-23 23:24:30 +02002312 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002313 err = mgmt_cmd_complete(sk, hdev->id,
2314 MGMT_OP_REMOVE_UUID,
2315 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002316 goto unlock;
2317 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002318
Johan Hedberg9246a862012-02-23 21:33:16 +02002319 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002320 }
2321
2322 found = 0;
2323
Johan Hedberg056341c2013-01-27 00:31:30 +02002324 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002325 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2326 continue;
2327
2328 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002329 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002330 found++;
2331 }
2332
2333 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002334 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2335 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002336 goto unlock;
2337 }
2338
Johan Hedberg9246a862012-02-23 21:33:16 +02002339update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002340 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002341
Johan Hedberg890ea892013-03-15 17:06:52 -05002342 update_class(&req);
2343 update_eir(&req);
2344
Johan Hedberg92da6092013-03-15 17:06:55 -05002345 err = hci_req_run(&req, remove_uuid_complete);
2346 if (err < 0) {
2347 if (err != -ENODATA)
2348 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002349
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002350 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2351 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002352 goto unlock;
2353 }
2354
2355 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002356 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002357 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002358 goto unlock;
2359 }
2360
2361 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002362
2363unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002364 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002365 return err;
2366}
2367
Marcel Holtmann1904a852015-01-11 13:50:44 -08002368static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002369{
2370 BT_DBG("status 0x%02x", status);
2371
2372 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2373}
2374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002375static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002377{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002378 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002379 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002380 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002381 int err;
2382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002384
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002385 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002386 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2387 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002388
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002389 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002390
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002391 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002392 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2393 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002394 goto unlock;
2395 }
2396
2397 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002398 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2399 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002400 goto unlock;
2401 }
2402
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002403 hdev->major_class = cp->major;
2404 hdev->minor_class = cp->minor;
2405
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002406 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002407 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2408 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002409 goto unlock;
2410 }
2411
Johan Hedberg890ea892013-03-15 17:06:52 -05002412 hci_req_init(&req, hdev);
2413
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002414 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002415 hci_dev_unlock(hdev);
2416 cancel_delayed_work_sync(&hdev->service_cache);
2417 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002418 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002419 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002420
Johan Hedberg890ea892013-03-15 17:06:52 -05002421 update_class(&req);
2422
Johan Hedberg92da6092013-03-15 17:06:55 -05002423 err = hci_req_run(&req, set_class_complete);
2424 if (err < 0) {
2425 if (err != -ENODATA)
2426 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002427
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002428 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2429 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002430 goto unlock;
2431 }
2432
2433 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002434 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002435 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002436 goto unlock;
2437 }
2438
2439 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002440
Johan Hedbergb5235a62012-02-21 14:32:24 +02002441unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002442 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002443 return err;
2444}
2445
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002446static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002447 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002448{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002449 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002450 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2451 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002452 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002453 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002454 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002455
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002456 BT_DBG("request for %s", hdev->name);
2457
2458 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002459 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2460 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002461
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002462 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002463 if (key_count > max_key_count) {
2464 BT_ERR("load_link_keys: too big key_count value %u",
2465 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002466 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2467 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002468 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002469
Johan Hedberg86742e12011-11-07 23:13:38 +02002470 expected_len = sizeof(*cp) + key_count *
2471 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002472 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002473 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002474 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002475 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2476 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002477 }
2478
Johan Hedberg4ae14302013-01-20 14:27:13 +02002479 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002480 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2481 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002483 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002484 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002485
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002486 for (i = 0; i < key_count; i++) {
2487 struct mgmt_link_key_info *key = &cp->keys[i];
2488
Marcel Holtmann8e991132014-01-10 02:07:25 -08002489 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002490 return mgmt_cmd_status(sk, hdev->id,
2491 MGMT_OP_LOAD_LINK_KEYS,
2492 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002493 }
2494
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002495 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002496
2497 hci_link_keys_clear(hdev);
2498
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002499 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002500 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002501 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002502 changed = hci_dev_test_and_clear_flag(hdev,
2503 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002504
2505 if (changed)
2506 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002507
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002508 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002509 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002510
Johan Hedberg58e92932014-06-24 14:00:26 +03002511 /* Always ignore debug keys and require a new pairing if
2512 * the user wants to use them.
2513 */
2514 if (key->type == HCI_LK_DEBUG_COMBINATION)
2515 continue;
2516
Johan Hedberg7652ff62014-06-24 13:15:49 +03002517 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2518 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002519 }
2520
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002521 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002522
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002523 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002524
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002525 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002526}
2527
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002528static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002529 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002530{
2531 struct mgmt_ev_device_unpaired ev;
2532
2533 bacpy(&ev.addr.bdaddr, bdaddr);
2534 ev.addr.type = addr_type;
2535
2536 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002537 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002538}
2539
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002540static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002541 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002542{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002543 struct mgmt_cp_unpair_device *cp = data;
2544 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002545 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002546 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002547 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002548 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002549 int err;
2550
Johan Hedberga8a1d192011-11-10 15:54:38 +02002551 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002552 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2553 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002554
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002555 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002556 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2557 MGMT_STATUS_INVALID_PARAMS,
2558 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002559
Johan Hedberg118da702013-01-20 14:27:20 +02002560 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002561 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2562 MGMT_STATUS_INVALID_PARAMS,
2563 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002564
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002565 hci_dev_lock(hdev);
2566
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002567 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002568 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2569 MGMT_STATUS_NOT_POWERED, &rp,
2570 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002571 goto unlock;
2572 }
2573
Johan Hedberge0b2b272014-02-18 17:14:31 +02002574 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002575 /* If disconnection is requested, then look up the
2576 * connection. If the remote device is connected, it
2577 * will be later used to terminate the link.
2578 *
2579 * Setting it to NULL explicitly will cause no
2580 * termination of the link.
2581 */
2582 if (cp->disconnect)
2583 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2584 &cp->addr.bdaddr);
2585 else
2586 conn = NULL;
2587
Johan Hedberg124f6e32012-02-09 13:50:12 +02002588 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002589 if (err < 0) {
2590 err = mgmt_cmd_complete(sk, hdev->id,
2591 MGMT_OP_UNPAIR_DEVICE,
2592 MGMT_STATUS_NOT_PAIRED, &rp,
2593 sizeof(rp));
2594 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002595 }
2596
Johan Hedbergec182f02015-10-21 18:03:03 +03002597 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002598 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002599
Johan Hedbergec182f02015-10-21 18:03:03 +03002600 /* LE address type */
2601 addr_type = le_addr_type(cp->addr.type);
2602
2603 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2604
2605 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002606 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002607 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2608 MGMT_STATUS_NOT_PAIRED, &rp,
2609 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002610 goto unlock;
2611 }
2612
Johan Hedbergec182f02015-10-21 18:03:03 +03002613 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2614 if (!conn) {
2615 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2616 goto done;
2617 }
2618
Johan Hedbergc81d5552015-10-22 09:38:35 +03002619 /* Abort any ongoing SMP pairing */
2620 smp_cancel_pairing(conn);
2621
Johan Hedbergec182f02015-10-21 18:03:03 +03002622 /* Defer clearing up the connection parameters until closing to
2623 * give a chance of keeping them if a repairing happens.
2624 */
2625 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2626
Johan Hedbergfc643612015-10-22 09:38:31 +03002627 /* Disable auto-connection parameters if present */
2628 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2629 if (params) {
2630 if (params->explicit_connect)
2631 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2632 else
2633 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2634 }
2635
Johan Hedbergec182f02015-10-21 18:03:03 +03002636 /* If disconnection is not requested, then clear the connection
2637 * variable so that the link is not terminated.
2638 */
2639 if (!cp->disconnect)
2640 conn = NULL;
2641
2642done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002643 /* If the connection variable is set, then termination of the
2644 * link is requested.
2645 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002646 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002647 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2648 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002649 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002650 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002651 }
2652
Johan Hedberg124f6e32012-02-09 13:50:12 +02002653 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002655 if (!cmd) {
2656 err = -ENOMEM;
2657 goto unlock;
2658 }
2659
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002660 cmd->cmd_complete = addr_cmd_complete;
2661
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002662 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002663 if (err < 0)
2664 mgmt_pending_remove(cmd);
2665
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002666unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002667 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002668 return err;
2669}
2670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002671static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002672 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002673{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002674 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002675 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002676 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002677 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002678 int err;
2679
2680 BT_DBG("");
2681
Johan Hedberg06a63b12013-01-20 14:27:21 +02002682 memset(&rp, 0, sizeof(rp));
2683 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2684 rp.addr.type = cp->addr.type;
2685
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002686 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002687 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2688 MGMT_STATUS_INVALID_PARAMS,
2689 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002690
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002691 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002692
2693 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002694 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2695 MGMT_STATUS_NOT_POWERED, &rp,
2696 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002697 goto failed;
2698 }
2699
Johan Hedberg333ae952015-03-17 13:48:47 +02002700 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002701 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2702 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002703 goto failed;
2704 }
2705
Andre Guedes591f47f2012-04-24 21:02:49 -03002706 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002707 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2708 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002709 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002710 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2711 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002712
Vishal Agarwalf9607272012-06-13 05:32:43 +05302713 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002714 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2715 MGMT_STATUS_NOT_CONNECTED, &rp,
2716 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002717 goto failed;
2718 }
2719
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002720 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002721 if (!cmd) {
2722 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002723 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002724 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002725
Johan Hedbergf5818c22014-12-05 13:36:02 +02002726 cmd->cmd_complete = generic_cmd_complete;
2727
Johan Hedberge3f2f922014-08-18 20:33:33 +03002728 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002729 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002730 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002731
2732failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002733 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002734 return err;
2735}
2736
Andre Guedes57c14772012-04-24 21:02:50 -03002737static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002738{
2739 switch (link_type) {
2740 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002741 switch (addr_type) {
2742 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002743 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002744
Johan Hedberg48264f02011-11-09 13:58:58 +02002745 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002746 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002747 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002748 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002749
Johan Hedberg4c659c32011-11-07 23:13:39 +02002750 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002751 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002752 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002753 }
2754}
2755
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002756static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2757 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002758{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002759 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002760 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002761 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002762 int err;
2763 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002764
2765 BT_DBG("");
2766
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002767 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002768
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002769 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002770 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2771 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002772 goto unlock;
2773 }
2774
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002775 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002776 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2777 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002778 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002779 }
2780
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002781 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002782 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002783 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002784 err = -ENOMEM;
2785 goto unlock;
2786 }
2787
Johan Hedberg2784eb42011-01-21 13:56:35 +02002788 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002789 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002790 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2791 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002792 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002793 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002794 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002795 continue;
2796 i++;
2797 }
2798
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002799 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002800
Johan Hedberg4c659c32011-11-07 23:13:39 +02002801 /* Recalculate length in case of filtered SCO connections, etc */
2802 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002803
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002804 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2805 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002806
Johan Hedberga38528f2011-01-22 06:46:43 +02002807 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002808
2809unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002810 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002811 return err;
2812}
2813
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002814static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002815 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002816{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002817 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002818 int err;
2819
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002820 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002821 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002822 if (!cmd)
2823 return -ENOMEM;
2824
Johan Hedbergd8457692012-02-17 14:24:57 +02002825 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002826 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002827 if (err < 0)
2828 mgmt_pending_remove(cmd);
2829
2830 return err;
2831}
2832
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002833static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002834 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002835{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002836 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002837 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002838 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002839 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002840 int err;
2841
2842 BT_DBG("");
2843
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002844 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002845
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002846 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002847 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2848 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002849 goto failed;
2850 }
2851
Johan Hedbergd8457692012-02-17 14:24:57 +02002852 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002853 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002854 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2855 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002856 goto failed;
2857 }
2858
2859 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002860 struct mgmt_cp_pin_code_neg_reply ncp;
2861
2862 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002863
2864 BT_ERR("PIN code is not 16 bytes long");
2865
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002866 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002867 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002868 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2869 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002870
2871 goto failed;
2872 }
2873
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002874 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002875 if (!cmd) {
2876 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002877 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002878 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002879
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002880 cmd->cmd_complete = addr_cmd_complete;
2881
Johan Hedbergd8457692012-02-17 14:24:57 +02002882 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002883 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002884 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002885
2886 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2887 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002888 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002889
2890failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002891 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002892 return err;
2893}
2894
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002895static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2896 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002897{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002898 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002899
2900 BT_DBG("");
2901
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002902 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002903 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2904 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002905
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002906 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002907
2908 hdev->io_capability = cp->io_capability;
2909
2910 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002911 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002913 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002914
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002915 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2916 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002917}
2918
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002919static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002920{
2921 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002922 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002923
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002924 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002925 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2926 continue;
2927
Johan Hedberge9a416b2011-02-19 12:05:56 -03002928 if (cmd->user_data != conn)
2929 continue;
2930
2931 return cmd;
2932 }
2933
2934 return NULL;
2935}
2936
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002937static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002938{
2939 struct mgmt_rp_pair_device rp;
2940 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002941 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002942
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002943 bacpy(&rp.addr.bdaddr, &conn->dst);
2944 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002945
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002946 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2947 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002948
2949 /* So we don't get further callbacks for this connection */
2950 conn->connect_cfm_cb = NULL;
2951 conn->security_cfm_cb = NULL;
2952 conn->disconn_cfm_cb = NULL;
2953
David Herrmann76a68ba2013-04-06 20:28:37 +02002954 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002955
2956 /* The device is paired so there is no need to remove
2957 * its connection parameters anymore.
2958 */
2959 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002960
2961 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002962
2963 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002964}
2965
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002966void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2967{
2968 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002969 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002970
2971 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002972 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002973 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002974 mgmt_pending_remove(cmd);
2975 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002976}
2977
Johan Hedberge9a416b2011-02-19 12:05:56 -03002978static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2979{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002980 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002981
2982 BT_DBG("status %u", status);
2983
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002984 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002985 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002986 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002987 return;
2988 }
2989
2990 cmd->cmd_complete(cmd, mgmt_status(status));
2991 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002992}
2993
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002994static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302995{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002996 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302997
2998 BT_DBG("status %u", status);
2999
3000 if (!status)
3001 return;
3002
3003 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003004 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303005 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003006 return;
3007 }
3008
3009 cmd->cmd_complete(cmd, mgmt_status(status));
3010 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303011}
3012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003013static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003015{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003016 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003017 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003018 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003019 u8 sec_level, auth_type;
3020 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003021 int err;
3022
3023 BT_DBG("");
3024
Szymon Jancf950a30e2013-01-18 12:48:07 +01003025 memset(&rp, 0, sizeof(rp));
3026 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3027 rp.addr.type = cp->addr.type;
3028
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003029 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003030 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3031 MGMT_STATUS_INVALID_PARAMS,
3032 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003033
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003034 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003035 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3036 MGMT_STATUS_INVALID_PARAMS,
3037 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003038
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003039 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003040
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003041 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003042 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3043 MGMT_STATUS_NOT_POWERED, &rp,
3044 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003045 goto unlock;
3046 }
3047
Johan Hedberg55e76b32015-03-10 22:34:40 +02003048 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3049 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3050 MGMT_STATUS_ALREADY_PAIRED, &rp,
3051 sizeof(rp));
3052 goto unlock;
3053 }
3054
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003055 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003056 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003057
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003058 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003059 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3060 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003061 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03003062 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03003063 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003064
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003065 /* When pairing a new device, it is expected to remember
3066 * this device for future connections. Adding the connection
3067 * parameter information ahead of time allows tracking
3068 * of the slave preferred values and will speed up any
3069 * further connection establishment.
3070 *
3071 * If connection parameters already exist, then they
3072 * will be kept and this function does nothing.
3073 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03003074 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3075
3076 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
3077 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003078
Jakub Pawlowskifa142222015-08-07 20:22:56 +02003079 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
3080 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02003081 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003082 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003083
Ville Tervo30e76272011-02-22 16:10:53 -03003084 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003085 int status;
3086
3087 if (PTR_ERR(conn) == -EBUSY)
3088 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003089 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3090 status = MGMT_STATUS_NOT_SUPPORTED;
3091 else if (PTR_ERR(conn) == -ECONNREFUSED)
3092 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003093 else
3094 status = MGMT_STATUS_CONNECT_FAILED;
3095
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003096 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3097 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003098 goto unlock;
3099 }
3100
3101 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003102 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003103 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3104 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003105 goto unlock;
3106 }
3107
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003108 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003109 if (!cmd) {
3110 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003111 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003112 goto unlock;
3113 }
3114
Johan Hedberg04ab2742014-12-05 13:36:04 +02003115 cmd->cmd_complete = pairing_complete;
3116
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003117 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003118 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003119 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003120 conn->security_cfm_cb = pairing_complete_cb;
3121 conn->disconn_cfm_cb = pairing_complete_cb;
3122 } else {
3123 conn->connect_cfm_cb = le_pairing_complete_cb;
3124 conn->security_cfm_cb = le_pairing_complete_cb;
3125 conn->disconn_cfm_cb = le_pairing_complete_cb;
3126 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003127
Johan Hedberge9a416b2011-02-19 12:05:56 -03003128 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003129 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003130
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003131 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003132 hci_conn_security(conn, sec_level, auth_type, true)) {
3133 cmd->cmd_complete(cmd, 0);
3134 mgmt_pending_remove(cmd);
3135 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003136
3137 err = 0;
3138
3139unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003140 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003141 return err;
3142}
3143
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3145 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003146{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003147 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003148 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003149 struct hci_conn *conn;
3150 int err;
3151
3152 BT_DBG("");
3153
Johan Hedberg28424702012-02-02 04:02:29 +02003154 hci_dev_lock(hdev);
3155
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003156 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003157 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3158 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003159 goto unlock;
3160 }
3161
Johan Hedberg333ae952015-03-17 13:48:47 +02003162 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003163 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003164 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3165 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003166 goto unlock;
3167 }
3168
3169 conn = cmd->user_data;
3170
3171 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003172 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3173 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003174 goto unlock;
3175 }
3176
Johan Hedberga511b352014-12-11 21:45:45 +02003177 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3178 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003179
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003180 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3181 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003182unlock:
3183 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003184 return err;
3185}
3186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003187static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003188 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003189 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003190{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003191 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003192 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003193 int err;
3194
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003195 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003196
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003197 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003198 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3199 MGMT_STATUS_NOT_POWERED, addr,
3200 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003201 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003202 }
3203
Johan Hedberg1707c602013-03-15 17:07:15 -05003204 if (addr->type == BDADDR_BREDR)
3205 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003206 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003207 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3208 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003209
Johan Hedberg272d90d2012-02-09 15:26:12 +02003210 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003211 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3212 MGMT_STATUS_NOT_CONNECTED, addr,
3213 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003214 goto done;
3215 }
3216
Johan Hedberg1707c602013-03-15 17:07:15 -05003217 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003218 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003219 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003220 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3221 MGMT_STATUS_SUCCESS, addr,
3222 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003223 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003224 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3225 MGMT_STATUS_FAILED, addr,
3226 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003227
Brian Gix47c15e22011-11-16 13:53:14 -08003228 goto done;
3229 }
3230
Johan Hedberg1707c602013-03-15 17:07:15 -05003231 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003232 if (!cmd) {
3233 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003234 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003235 }
3236
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003237 cmd->cmd_complete = addr_cmd_complete;
3238
Brian Gix0df4c182011-11-16 13:53:13 -08003239 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003240 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3241 struct hci_cp_user_passkey_reply cp;
3242
Johan Hedberg1707c602013-03-15 17:07:15 -05003243 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003244 cp.passkey = passkey;
3245 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3246 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003247 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3248 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003249
Johan Hedberga664b5b2011-02-19 12:06:02 -03003250 if (err < 0)
3251 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003252
Brian Gix0df4c182011-11-16 13:53:13 -08003253done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003254 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003255 return err;
3256}
3257
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303258static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3259 void *data, u16 len)
3260{
3261 struct mgmt_cp_pin_code_neg_reply *cp = data;
3262
3263 BT_DBG("");
3264
Johan Hedberg1707c602013-03-15 17:07:15 -05003265 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303266 MGMT_OP_PIN_CODE_NEG_REPLY,
3267 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3268}
3269
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003270static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3271 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003272{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003273 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003274
3275 BT_DBG("");
3276
3277 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003278 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3279 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003280
Johan Hedberg1707c602013-03-15 17:07:15 -05003281 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003282 MGMT_OP_USER_CONFIRM_REPLY,
3283 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003284}
3285
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003286static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003287 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003288{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003289 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003290
3291 BT_DBG("");
3292
Johan Hedberg1707c602013-03-15 17:07:15 -05003293 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003294 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3295 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003296}
3297
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003298static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3299 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003300{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003301 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003302
3303 BT_DBG("");
3304
Johan Hedberg1707c602013-03-15 17:07:15 -05003305 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003306 MGMT_OP_USER_PASSKEY_REPLY,
3307 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003308}
3309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003310static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003311 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003312{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003313 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003314
3315 BT_DBG("");
3316
Johan Hedberg1707c602013-03-15 17:07:15 -05003317 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003318 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3319 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003320}
3321
Johan Hedberg13928972013-03-15 17:07:00 -05003322static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003323{
Johan Hedberg13928972013-03-15 17:07:00 -05003324 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003325 struct hci_cp_write_local_name cp;
3326
Johan Hedberg13928972013-03-15 17:07:00 -05003327 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003328
Johan Hedberg890ea892013-03-15 17:06:52 -05003329 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003330}
3331
Marcel Holtmann1904a852015-01-11 13:50:44 -08003332static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003333{
3334 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003335 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003336
3337 BT_DBG("status 0x%02x", status);
3338
3339 hci_dev_lock(hdev);
3340
Johan Hedberg333ae952015-03-17 13:48:47 +02003341 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003342 if (!cmd)
3343 goto unlock;
3344
3345 cp = cmd->param;
3346
3347 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003348 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3349 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003350 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003351 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3352 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003353
3354 mgmt_pending_remove(cmd);
3355
3356unlock:
3357 hci_dev_unlock(hdev);
3358}
3359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003360static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003361 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003362{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003363 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003364 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003365 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003366 int err;
3367
3368 BT_DBG("");
3369
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003370 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003371
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003372 /* If the old values are the same as the new ones just return a
3373 * direct command complete event.
3374 */
3375 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3376 !memcmp(hdev->short_name, cp->short_name,
3377 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003378 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3379 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003380 goto failed;
3381 }
3382
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003383 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003384
Johan Hedbergb5235a62012-02-21 14:32:24 +02003385 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003386 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003387
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003388 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3389 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003390 if (err < 0)
3391 goto failed;
3392
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003393 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3394 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003395
Johan Hedbergb5235a62012-02-21 14:32:24 +02003396 goto failed;
3397 }
3398
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003399 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003400 if (!cmd) {
3401 err = -ENOMEM;
3402 goto failed;
3403 }
3404
Johan Hedberg13928972013-03-15 17:07:00 -05003405 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3406
Johan Hedberg890ea892013-03-15 17:06:52 -05003407 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003408
3409 if (lmp_bredr_capable(hdev)) {
3410 update_name(&req);
3411 update_eir(&req);
3412 }
3413
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003414 /* The name is stored in the scan response data and so
3415 * no need to udpate the advertising data here.
3416 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003417 if (lmp_le_capable(hdev))
Johan Hedbergf2252572015-11-18 12:49:20 +02003418 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Johan Hedberg3f985052013-03-15 17:07:02 -05003419
Johan Hedberg13928972013-03-15 17:07:00 -05003420 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003421 if (err < 0)
3422 mgmt_pending_remove(cmd);
3423
3424failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003425 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003426 return err;
3427}
3428
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003429static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3430 u16 opcode, struct sk_buff *skb)
3431{
3432 struct mgmt_rp_read_local_oob_data mgmt_rp;
3433 size_t rp_size = sizeof(mgmt_rp);
3434 struct mgmt_pending_cmd *cmd;
3435
3436 BT_DBG("%s status %u", hdev->name, status);
3437
3438 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3439 if (!cmd)
3440 return;
3441
3442 if (status || !skb) {
3443 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3444 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3445 goto remove;
3446 }
3447
3448 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3449
3450 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3451 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3452
3453 if (skb->len < sizeof(*rp)) {
3454 mgmt_cmd_status(cmd->sk, hdev->id,
3455 MGMT_OP_READ_LOCAL_OOB_DATA,
3456 MGMT_STATUS_FAILED);
3457 goto remove;
3458 }
3459
3460 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3461 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3462
3463 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3464 } else {
3465 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3466
3467 if (skb->len < sizeof(*rp)) {
3468 mgmt_cmd_status(cmd->sk, hdev->id,
3469 MGMT_OP_READ_LOCAL_OOB_DATA,
3470 MGMT_STATUS_FAILED);
3471 goto remove;
3472 }
3473
3474 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3475 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3476
3477 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3478 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3479 }
3480
3481 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3482 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3483
3484remove:
3485 mgmt_pending_remove(cmd);
3486}
3487
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003488static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003489 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003490{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003491 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003492 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003493 int err;
3494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003495 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003497 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003498
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003499 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003500 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3501 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003502 goto unlock;
3503 }
3504
Andre Guedes9a1a1992012-07-24 15:03:48 -03003505 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003506 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3507 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003508 goto unlock;
3509 }
3510
Johan Hedberg333ae952015-03-17 13:48:47 +02003511 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003512 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3513 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003514 goto unlock;
3515 }
3516
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003517 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003518 if (!cmd) {
3519 err = -ENOMEM;
3520 goto unlock;
3521 }
3522
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003523 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003524
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003525 if (bredr_sc_enabled(hdev))
3526 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3527 else
3528 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3529
3530 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003531 if (err < 0)
3532 mgmt_pending_remove(cmd);
3533
3534unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003535 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003536 return err;
3537}
3538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003539static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003540 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003541{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003542 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003543 int err;
3544
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003545 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003546
Johan Hedberg5d57e792015-01-23 10:10:38 +02003547 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003548 return mgmt_cmd_complete(sk, hdev->id,
3549 MGMT_OP_ADD_REMOTE_OOB_DATA,
3550 MGMT_STATUS_INVALID_PARAMS,
3551 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003552
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003553 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003554
Marcel Holtmannec109112014-01-10 02:07:30 -08003555 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3556 struct mgmt_cp_add_remote_oob_data *cp = data;
3557 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003558
Johan Hedbergc19a4952014-11-17 20:52:19 +02003559 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003560 err = mgmt_cmd_complete(sk, hdev->id,
3561 MGMT_OP_ADD_REMOTE_OOB_DATA,
3562 MGMT_STATUS_INVALID_PARAMS,
3563 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003564 goto unlock;
3565 }
3566
Marcel Holtmannec109112014-01-10 02:07:30 -08003567 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003568 cp->addr.type, cp->hash,
3569 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003570 if (err < 0)
3571 status = MGMT_STATUS_FAILED;
3572 else
3573 status = MGMT_STATUS_SUCCESS;
3574
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003575 err = mgmt_cmd_complete(sk, hdev->id,
3576 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3577 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003578 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3579 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003580 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003581 u8 status;
3582
Johan Hedberg86df9202014-10-26 20:52:27 +01003583 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003584 /* Enforce zero-valued 192-bit parameters as
3585 * long as legacy SMP OOB isn't implemented.
3586 */
3587 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3588 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003589 err = mgmt_cmd_complete(sk, hdev->id,
3590 MGMT_OP_ADD_REMOTE_OOB_DATA,
3591 MGMT_STATUS_INVALID_PARAMS,
3592 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003593 goto unlock;
3594 }
3595
Johan Hedberg86df9202014-10-26 20:52:27 +01003596 rand192 = NULL;
3597 hash192 = NULL;
3598 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003599 /* In case one of the P-192 values is set to zero,
3600 * then just disable OOB data for P-192.
3601 */
3602 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3603 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3604 rand192 = NULL;
3605 hash192 = NULL;
3606 } else {
3607 rand192 = cp->rand192;
3608 hash192 = cp->hash192;
3609 }
3610 }
3611
3612 /* In case one of the P-256 values is set to zero, then just
3613 * disable OOB data for P-256.
3614 */
3615 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3616 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3617 rand256 = NULL;
3618 hash256 = NULL;
3619 } else {
3620 rand256 = cp->rand256;
3621 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003622 }
3623
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003624 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003625 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003626 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003627 if (err < 0)
3628 status = MGMT_STATUS_FAILED;
3629 else
3630 status = MGMT_STATUS_SUCCESS;
3631
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003632 err = mgmt_cmd_complete(sk, hdev->id,
3633 MGMT_OP_ADD_REMOTE_OOB_DATA,
3634 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003635 } else {
3636 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003637 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3638 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003639 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003640
Johan Hedbergc19a4952014-11-17 20:52:19 +02003641unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003642 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003643 return err;
3644}
3645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003646static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003647 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003648{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003649 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003650 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003651 int err;
3652
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003653 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003654
Johan Hedbergc19a4952014-11-17 20:52:19 +02003655 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003656 return mgmt_cmd_complete(sk, hdev->id,
3657 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3658 MGMT_STATUS_INVALID_PARAMS,
3659 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003661 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003662
Johan Hedbergeedbd582014-11-15 09:34:23 +02003663 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3664 hci_remote_oob_data_clear(hdev);
3665 status = MGMT_STATUS_SUCCESS;
3666 goto done;
3667 }
3668
Johan Hedberg6928a922014-10-26 20:46:09 +01003669 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003670 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003671 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003672 else
Szymon Janca6785be2012-12-13 15:11:21 +01003673 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003674
Johan Hedbergeedbd582014-11-15 09:34:23 +02003675done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003676 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3677 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003678
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003679 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003680 return err;
3681}
3682
Johan Hedberge68f0722015-11-11 08:30:30 +02003683void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003684{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003685 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003686
Andre Guedes7c307722013-04-30 15:29:28 -03003687 BT_DBG("status %d", status);
3688
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003689 hci_dev_lock(hdev);
3690
Johan Hedberg333ae952015-03-17 13:48:47 +02003691 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003692 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003693 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003694
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003695 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003696 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003697 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003698 }
3699
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003700 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003701}
3702
Johan Hedberg591752a2015-11-11 08:11:24 +02003703static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3704 uint8_t *mgmt_status)
3705{
3706 switch (type) {
3707 case DISCOV_TYPE_LE:
3708 *mgmt_status = mgmt_le_support(hdev);
3709 if (*mgmt_status)
3710 return false;
3711 break;
3712 case DISCOV_TYPE_INTERLEAVED:
3713 *mgmt_status = mgmt_le_support(hdev);
3714 if (*mgmt_status)
3715 return false;
3716 /* Intentional fall-through */
3717 case DISCOV_TYPE_BREDR:
3718 *mgmt_status = mgmt_bredr_support(hdev);
3719 if (*mgmt_status)
3720 return false;
3721 break;
3722 default:
3723 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3724 return false;
3725 }
3726
3727 return true;
3728}
3729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003730static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003731 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003732{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003733 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003734 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003735 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003736 int err;
3737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003738 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003739
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003740 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003741
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003742 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003743 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3744 MGMT_STATUS_NOT_POWERED,
3745 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003746 goto failed;
3747 }
3748
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003749 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003750 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003751 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3752 MGMT_STATUS_BUSY, &cp->type,
3753 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003754 goto failed;
3755 }
3756
Johan Hedberg591752a2015-11-11 08:11:24 +02003757 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3758 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3759 status, &cp->type, sizeof(cp->type));
3760 goto failed;
3761 }
3762
Marcel Holtmann22078802014-12-05 11:45:22 +01003763 /* Clear the discovery filter first to free any previously
3764 * allocated memory for the UUID list.
3765 */
3766 hci_discovery_filter_clear(hdev);
3767
Andre Guedes4aab14e2012-02-17 20:39:36 -03003768 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003769 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003770
Johan Hedberge68f0722015-11-11 08:30:30 +02003771 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
3772 if (!cmd) {
3773 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003774 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003775 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003776
Johan Hedberge68f0722015-11-11 08:30:30 +02003777 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003778
3779 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003780 queue_work(hdev->req_workqueue, &hdev->discov_update);
3781 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003782
3783failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003784 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003785 return err;
3786}
3787
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003788static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3789 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003790{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003791 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3792 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003793}
3794
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003795static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3796 void *data, u16 len)
3797{
3798 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003799 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003800 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3801 u16 uuid_count, expected_len;
3802 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003803 int err;
3804
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003805 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003806
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003807 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003808
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003809 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003810 err = mgmt_cmd_complete(sk, hdev->id,
3811 MGMT_OP_START_SERVICE_DISCOVERY,
3812 MGMT_STATUS_NOT_POWERED,
3813 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003814 goto failed;
3815 }
3816
3817 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003818 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003819 err = mgmt_cmd_complete(sk, hdev->id,
3820 MGMT_OP_START_SERVICE_DISCOVERY,
3821 MGMT_STATUS_BUSY, &cp->type,
3822 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003823 goto failed;
3824 }
3825
3826 uuid_count = __le16_to_cpu(cp->uuid_count);
3827 if (uuid_count > max_uuid_count) {
3828 BT_ERR("service_discovery: too big uuid_count value %u",
3829 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003830 err = mgmt_cmd_complete(sk, hdev->id,
3831 MGMT_OP_START_SERVICE_DISCOVERY,
3832 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3833 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003834 goto failed;
3835 }
3836
3837 expected_len = sizeof(*cp) + uuid_count * 16;
3838 if (expected_len != len) {
3839 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3840 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003841 err = mgmt_cmd_complete(sk, hdev->id,
3842 MGMT_OP_START_SERVICE_DISCOVERY,
3843 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3844 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003845 goto failed;
3846 }
3847
Johan Hedberg591752a2015-11-11 08:11:24 +02003848 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3849 err = mgmt_cmd_complete(sk, hdev->id,
3850 MGMT_OP_START_SERVICE_DISCOVERY,
3851 status, &cp->type, sizeof(cp->type));
3852 goto failed;
3853 }
3854
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003855 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003856 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003857 if (!cmd) {
3858 err = -ENOMEM;
3859 goto failed;
3860 }
3861
Johan Hedberg2922a942014-12-05 13:36:06 +02003862 cmd->cmd_complete = service_discovery_cmd_complete;
3863
Marcel Holtmann22078802014-12-05 11:45:22 +01003864 /* Clear the discovery filter first to free any previously
3865 * allocated memory for the UUID list.
3866 */
3867 hci_discovery_filter_clear(hdev);
3868
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003869 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003870 hdev->discovery.type = cp->type;
3871 hdev->discovery.rssi = cp->rssi;
3872 hdev->discovery.uuid_count = uuid_count;
3873
3874 if (uuid_count > 0) {
3875 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3876 GFP_KERNEL);
3877 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003878 err = mgmt_cmd_complete(sk, hdev->id,
3879 MGMT_OP_START_SERVICE_DISCOVERY,
3880 MGMT_STATUS_FAILED,
3881 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003882 mgmt_pending_remove(cmd);
3883 goto failed;
3884 }
3885 }
3886
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003887 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003888 queue_work(hdev->req_workqueue, &hdev->discov_update);
3889 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003890
3891failed:
3892 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003893 return err;
3894}
3895
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003896void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003897{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003898 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003899
Andre Guedes0e05bba2013-04-30 15:29:33 -03003900 BT_DBG("status %d", status);
3901
3902 hci_dev_lock(hdev);
3903
Johan Hedberg333ae952015-03-17 13:48:47 +02003904 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003905 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003906 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003907 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003908 }
3909
Andre Guedes0e05bba2013-04-30 15:29:33 -03003910 hci_dev_unlock(hdev);
3911}
3912
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003913static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003914 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003915{
Johan Hedbergd9306502012-02-20 23:25:18 +02003916 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003917 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003918 int err;
3919
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003920 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003921
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003922 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003923
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003924 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003925 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3926 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3927 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003928 goto unlock;
3929 }
3930
3931 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003932 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3933 MGMT_STATUS_INVALID_PARAMS,
3934 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003935 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003936 }
3937
Johan Hedberg2922a942014-12-05 13:36:06 +02003938 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003939 if (!cmd) {
3940 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003941 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003942 }
3943
Johan Hedberg2922a942014-12-05 13:36:06 +02003944 cmd->cmd_complete = generic_cmd_complete;
3945
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003946 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3947 queue_work(hdev->req_workqueue, &hdev->discov_update);
3948 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003949
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003950unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003951 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003952 return err;
3953}
3954
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003955static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003956 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003957{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003958 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003959 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003960 int err;
3961
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003962 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003963
Johan Hedberg561aafb2012-01-04 13:31:59 +02003964 hci_dev_lock(hdev);
3965
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003966 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003967 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3968 MGMT_STATUS_FAILED, &cp->addr,
3969 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003970 goto failed;
3971 }
3972
Johan Hedberga198e7b2012-02-17 14:27:06 +02003973 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003974 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003975 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3976 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3977 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003978 goto failed;
3979 }
3980
3981 if (cp->name_known) {
3982 e->name_state = NAME_KNOWN;
3983 list_del(&e->list);
3984 } else {
3985 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003986 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003987 }
3988
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003989 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3990 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003991
3992failed:
3993 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003994 return err;
3995}
3996
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003997static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003998 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003999{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004000 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004001 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004002 int err;
4003
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004004 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004005
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004006 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004007 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4008 MGMT_STATUS_INVALID_PARAMS,
4009 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004010
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004011 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004012
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004013 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4014 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004015 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004016 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004017 goto done;
4018 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004019
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004020 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4021 sk);
4022 status = MGMT_STATUS_SUCCESS;
4023
4024done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004025 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4026 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004028 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004029
4030 return err;
4031}
4032
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004033static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004034 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004035{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004036 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004037 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004038 int err;
4039
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004040 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004041
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004042 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004043 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4044 MGMT_STATUS_INVALID_PARAMS,
4045 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004046
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004047 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004048
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004049 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4050 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004051 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004052 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004053 goto done;
4054 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004055
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004056 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4057 sk);
4058 status = MGMT_STATUS_SUCCESS;
4059
4060done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004061 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4062 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004063
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004064 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004065
4066 return err;
4067}
4068
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004069static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4070 u16 len)
4071{
4072 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004073 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004074 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004075 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004076
4077 BT_DBG("%s", hdev->name);
4078
Szymon Jancc72d4b82012-03-16 16:02:57 +01004079 source = __le16_to_cpu(cp->source);
4080
4081 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004082 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4083 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004084
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004085 hci_dev_lock(hdev);
4086
Szymon Jancc72d4b82012-03-16 16:02:57 +01004087 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004088 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4089 hdev->devid_product = __le16_to_cpu(cp->product);
4090 hdev->devid_version = __le16_to_cpu(cp->version);
4091
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004092 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4093 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004094
Johan Hedberg890ea892013-03-15 17:06:52 -05004095 hci_req_init(&req, hdev);
4096 update_eir(&req);
4097 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004098
4099 hci_dev_unlock(hdev);
4100
4101 return err;
4102}
4103
Arman Uguray24b4f382015-03-23 15:57:12 -07004104static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4105 u16 opcode)
4106{
4107 BT_DBG("status %d", status);
4108}
4109
Marcel Holtmann1904a852015-01-11 13:50:44 -08004110static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4111 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004112{
4113 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004114 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004115 u8 instance;
4116 struct adv_info *adv_instance;
4117 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004118
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304119 hci_dev_lock(hdev);
4120
Johan Hedberg4375f102013-09-25 13:26:10 +03004121 if (status) {
4122 u8 mgmt_err = mgmt_status(status);
4123
4124 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4125 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304126 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004127 }
4128
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004129 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004130 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004131 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004132 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004133
Johan Hedberg4375f102013-09-25 13:26:10 +03004134 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4135 &match);
4136
4137 new_settings(hdev, match.sk);
4138
4139 if (match.sk)
4140 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304141
Arman Uguray24b4f382015-03-23 15:57:12 -07004142 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004143 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004144 */
4145 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004146 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
4147 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004148 goto unlock;
4149
Florian Grandel7816b822015-06-18 03:16:45 +02004150 instance = hdev->cur_adv_instance;
4151 if (!instance) {
4152 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4153 struct adv_info, list);
4154 if (!adv_instance)
4155 goto unlock;
4156
4157 instance = adv_instance->instance;
4158 }
4159
Arman Uguray24b4f382015-03-23 15:57:12 -07004160 hci_req_init(&req, hdev);
4161
Johan Hedbergf2252572015-11-18 12:49:20 +02004162 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004163
Florian Grandel7816b822015-06-18 03:16:45 +02004164 if (!err)
4165 err = hci_req_run(&req, enable_advertising_instance);
4166
4167 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07004168 BT_ERR("Failed to re-configure advertising");
4169
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304170unlock:
4171 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004172}
4173
Marcel Holtmann21b51872013-10-10 09:47:53 -07004174static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4175 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004176{
4177 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004178 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004179 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004180 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004181 int err;
4182
4183 BT_DBG("request for %s", hdev->name);
4184
Johan Hedberge6fe7982013-10-02 15:45:22 +03004185 status = mgmt_le_support(hdev);
4186 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004187 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4188 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004189
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004190 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004191 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4192 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004193
4194 hci_dev_lock(hdev);
4195
4196 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004197
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004198 /* The following conditions are ones which mean that we should
4199 * not do any HCI communication but directly send a mgmt
4200 * response to user space (after toggling the flag if
4201 * necessary).
4202 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004203 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004204 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4205 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004206 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004207 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004208 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004209 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004210
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004211 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004212 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004213 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004214 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004215 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004216 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004217 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004218 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004219 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004220 }
4221
4222 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4223 if (err < 0)
4224 goto unlock;
4225
4226 if (changed)
4227 err = new_settings(hdev, sk);
4228
4229 goto unlock;
4230 }
4231
Johan Hedberg333ae952015-03-17 13:48:47 +02004232 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4233 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004234 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4235 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004236 goto unlock;
4237 }
4238
4239 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4240 if (!cmd) {
4241 err = -ENOMEM;
4242 goto unlock;
4243 }
4244
4245 hci_req_init(&req, hdev);
4246
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004247 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004248 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004249 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004250 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004251
Florian Grandel7816b822015-06-18 03:16:45 +02004252 cancel_adv_timeout(hdev);
4253
Arman Uguray24b4f382015-03-23 15:57:12 -07004254 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004255 /* Switch to instance "0" for the Set Advertising setting.
4256 * We cannot use update_[adv|scan_rsp]_data() here as the
4257 * HCI_ADVERTISING flag is not yet set.
4258 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004259 __hci_req_update_adv_data(&req, 0x00);
4260 __hci_req_update_scan_rsp_data(&req, 0x00);
4261 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004262 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004263 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004264 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004265
4266 err = hci_req_run(&req, set_advertising_complete);
4267 if (err < 0)
4268 mgmt_pending_remove(cmd);
4269
4270unlock:
4271 hci_dev_unlock(hdev);
4272 return err;
4273}
4274
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004275static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4276 void *data, u16 len)
4277{
4278 struct mgmt_cp_set_static_address *cp = data;
4279 int err;
4280
4281 BT_DBG("%s", hdev->name);
4282
Marcel Holtmann62af4442013-10-02 22:10:32 -07004283 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004284 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4285 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004286
4287 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004288 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4289 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004290
4291 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4292 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004293 return mgmt_cmd_status(sk, hdev->id,
4294 MGMT_OP_SET_STATIC_ADDRESS,
4295 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004296
4297 /* Two most significant bits shall be set */
4298 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004299 return mgmt_cmd_status(sk, hdev->id,
4300 MGMT_OP_SET_STATIC_ADDRESS,
4301 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004302 }
4303
4304 hci_dev_lock(hdev);
4305
4306 bacpy(&hdev->static_addr, &cp->bdaddr);
4307
Marcel Holtmann93690c22015-03-06 10:11:21 -08004308 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4309 if (err < 0)
4310 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004311
Marcel Holtmann93690c22015-03-06 10:11:21 -08004312 err = new_settings(hdev, sk);
4313
4314unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004315 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004316 return err;
4317}
4318
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004319static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4320 void *data, u16 len)
4321{
4322 struct mgmt_cp_set_scan_params *cp = data;
4323 __u16 interval, window;
4324 int err;
4325
4326 BT_DBG("%s", hdev->name);
4327
4328 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004329 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4330 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004331
4332 interval = __le16_to_cpu(cp->interval);
4333
4334 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004335 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4336 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004337
4338 window = __le16_to_cpu(cp->window);
4339
4340 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004341 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4342 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004343
Marcel Holtmann899e1072013-10-14 09:55:32 -07004344 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004345 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4346 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004347
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004348 hci_dev_lock(hdev);
4349
4350 hdev->le_scan_interval = interval;
4351 hdev->le_scan_window = window;
4352
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004353 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4354 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004355
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004356 /* If background scan is running, restart it so new parameters are
4357 * loaded.
4358 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004359 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004360 hdev->discovery.state == DISCOVERY_STOPPED) {
4361 struct hci_request req;
4362
4363 hci_req_init(&req, hdev);
4364
4365 hci_req_add_le_scan_disable(&req);
4366 hci_req_add_le_passive_scan(&req);
4367
4368 hci_req_run(&req, NULL);
4369 }
4370
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004371 hci_dev_unlock(hdev);
4372
4373 return err;
4374}
4375
Marcel Holtmann1904a852015-01-11 13:50:44 -08004376static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4377 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004378{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004379 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004380
4381 BT_DBG("status 0x%02x", status);
4382
4383 hci_dev_lock(hdev);
4384
Johan Hedberg333ae952015-03-17 13:48:47 +02004385 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004386 if (!cmd)
4387 goto unlock;
4388
4389 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004390 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4391 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004392 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004393 struct mgmt_mode *cp = cmd->param;
4394
4395 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004396 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004397 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004398 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004399
Johan Hedberg33e38b32013-03-15 17:07:05 -05004400 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4401 new_settings(hdev, cmd->sk);
4402 }
4403
4404 mgmt_pending_remove(cmd);
4405
4406unlock:
4407 hci_dev_unlock(hdev);
4408}
4409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004410static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004411 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004412{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004413 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004414 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004415 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004416 int err;
4417
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004418 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004419
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004420 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004421 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004422 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4423 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004424
Johan Hedberga7e80f22013-01-09 16:05:19 +02004425 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004426 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4427 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004428
Antti Julkuf6422ec2011-06-22 13:11:56 +03004429 hci_dev_lock(hdev);
4430
Johan Hedberg333ae952015-03-17 13:48:47 +02004431 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004432 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4433 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004434 goto unlock;
4435 }
4436
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004437 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004438 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4439 hdev);
4440 goto unlock;
4441 }
4442
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004443 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004444 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004445 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4446 hdev);
4447 new_settings(hdev, sk);
4448 goto unlock;
4449 }
4450
Johan Hedberg33e38b32013-03-15 17:07:05 -05004451 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4452 data, len);
4453 if (!cmd) {
4454 err = -ENOMEM;
4455 goto unlock;
4456 }
4457
4458 hci_req_init(&req, hdev);
4459
Johan Hedberg406d7802013-03-15 17:07:09 -05004460 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004461
4462 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004463 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004464 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4465 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004466 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004467 }
4468
Johan Hedberg33e38b32013-03-15 17:07:05 -05004469unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004470 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004471
Antti Julkuf6422ec2011-06-22 13:11:56 +03004472 return err;
4473}
4474
Marcel Holtmann1904a852015-01-11 13:50:44 -08004475static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004476{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004477 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004478
4479 BT_DBG("status 0x%02x", status);
4480
4481 hci_dev_lock(hdev);
4482
Johan Hedberg333ae952015-03-17 13:48:47 +02004483 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004484 if (!cmd)
4485 goto unlock;
4486
4487 if (status) {
4488 u8 mgmt_err = mgmt_status(status);
4489
4490 /* We need to restore the flag if related HCI commands
4491 * failed.
4492 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004493 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004494
Johan Hedberga69e8372015-03-06 21:08:53 +02004495 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004496 } else {
4497 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4498 new_settings(hdev, cmd->sk);
4499 }
4500
4501 mgmt_pending_remove(cmd);
4502
4503unlock:
4504 hci_dev_unlock(hdev);
4505}
4506
4507static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4508{
4509 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004510 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004511 struct hci_request req;
4512 int err;
4513
4514 BT_DBG("request for %s", hdev->name);
4515
4516 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004517 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4518 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004519
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004520 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004521 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4522 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004523
4524 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004525 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4526 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004527
4528 hci_dev_lock(hdev);
4529
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004530 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004531 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4532 goto unlock;
4533 }
4534
4535 if (!hdev_is_powered(hdev)) {
4536 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004537 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4538 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4539 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4540 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4541 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004542 }
4543
Marcel Holtmannce05d602015-03-13 02:11:03 -07004544 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004545
4546 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4547 if (err < 0)
4548 goto unlock;
4549
4550 err = new_settings(hdev, sk);
4551 goto unlock;
4552 }
4553
4554 /* Reject disabling when powered on */
4555 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004556 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4557 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004558 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004559 } else {
4560 /* When configuring a dual-mode controller to operate
4561 * with LE only and using a static address, then switching
4562 * BR/EDR back on is not allowed.
4563 *
4564 * Dual-mode controllers shall operate with the public
4565 * address as its identity address for BR/EDR and LE. So
4566 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004567 *
4568 * The same restrictions applies when secure connections
4569 * has been enabled. For BR/EDR this is a controller feature
4570 * while for LE it is a host stack feature. This means that
4571 * switching BR/EDR back on when secure connections has been
4572 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004573 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004574 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004575 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004576 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004577 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4578 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004579 goto unlock;
4580 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004581 }
4582
Johan Hedberg333ae952015-03-17 13:48:47 +02004583 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004584 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4585 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004586 goto unlock;
4587 }
4588
4589 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4590 if (!cmd) {
4591 err = -ENOMEM;
4592 goto unlock;
4593 }
4594
Johan Hedbergf2252572015-11-18 12:49:20 +02004595 /* We need to flip the bit already here so that
4596 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004597 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004598 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004599
4600 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004601
Johan Hedberg432df052014-08-01 11:13:31 +03004602 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004603 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004604
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004605 /* Since only the advertising data flags will change, there
4606 * is no need to update the scan response data.
4607 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004608 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004609
Johan Hedberg0663ca22013-10-02 13:43:14 +03004610 err = hci_req_run(&req, set_bredr_complete);
4611 if (err < 0)
4612 mgmt_pending_remove(cmd);
4613
4614unlock:
4615 hci_dev_unlock(hdev);
4616 return err;
4617}
4618
Johan Hedberga1443f52015-01-23 15:42:46 +02004619static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4620{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004621 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004622 struct mgmt_mode *cp;
4623
4624 BT_DBG("%s status %u", hdev->name, status);
4625
4626 hci_dev_lock(hdev);
4627
Johan Hedberg333ae952015-03-17 13:48:47 +02004628 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004629 if (!cmd)
4630 goto unlock;
4631
4632 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004633 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4634 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004635 goto remove;
4636 }
4637
4638 cp = cmd->param;
4639
4640 switch (cp->val) {
4641 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004642 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4643 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004644 break;
4645 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004646 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004647 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004648 break;
4649 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004650 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4651 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004652 break;
4653 }
4654
4655 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4656 new_settings(hdev, cmd->sk);
4657
4658remove:
4659 mgmt_pending_remove(cmd);
4660unlock:
4661 hci_dev_unlock(hdev);
4662}
4663
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004664static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4665 void *data, u16 len)
4666{
4667 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004668 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004669 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004670 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004671 int err;
4672
4673 BT_DBG("request for %s", hdev->name);
4674
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004675 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004676 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4678 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004679
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004680 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004681 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004682 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004683 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4684 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004685
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004686 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004687 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004688 MGMT_STATUS_INVALID_PARAMS);
4689
4690 hci_dev_lock(hdev);
4691
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004692 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004693 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004694 bool changed;
4695
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004696 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004697 changed = !hci_dev_test_and_set_flag(hdev,
4698 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004699 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004700 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004701 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004702 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004703 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004704 changed = hci_dev_test_and_clear_flag(hdev,
4705 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004706 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004707 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004708
4709 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4710 if (err < 0)
4711 goto failed;
4712
4713 if (changed)
4714 err = new_settings(hdev, sk);
4715
4716 goto failed;
4717 }
4718
Johan Hedberg333ae952015-03-17 13:48:47 +02004719 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004720 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4721 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004722 goto failed;
4723 }
4724
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004725 val = !!cp->val;
4726
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004727 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4728 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004729 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4730 goto failed;
4731 }
4732
4733 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4734 if (!cmd) {
4735 err = -ENOMEM;
4736 goto failed;
4737 }
4738
Johan Hedberga1443f52015-01-23 15:42:46 +02004739 hci_req_init(&req, hdev);
4740 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4741 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004742 if (err < 0) {
4743 mgmt_pending_remove(cmd);
4744 goto failed;
4745 }
4746
4747failed:
4748 hci_dev_unlock(hdev);
4749 return err;
4750}
4751
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004752static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4753 void *data, u16 len)
4754{
4755 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004756 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004757 int err;
4758
4759 BT_DBG("request for %s", hdev->name);
4760
Johan Hedbergb97109792014-06-24 14:00:28 +03004761 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004762 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4763 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004764
4765 hci_dev_lock(hdev);
4766
4767 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004768 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004769 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004770 changed = hci_dev_test_and_clear_flag(hdev,
4771 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004772
Johan Hedbergb97109792014-06-24 14:00:28 +03004773 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004774 use_changed = !hci_dev_test_and_set_flag(hdev,
4775 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004776 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004777 use_changed = hci_dev_test_and_clear_flag(hdev,
4778 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004779
4780 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004781 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004782 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4783 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4784 sizeof(mode), &mode);
4785 }
4786
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004787 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4788 if (err < 0)
4789 goto unlock;
4790
4791 if (changed)
4792 err = new_settings(hdev, sk);
4793
4794unlock:
4795 hci_dev_unlock(hdev);
4796 return err;
4797}
4798
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004799static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4800 u16 len)
4801{
4802 struct mgmt_cp_set_privacy *cp = cp_data;
4803 bool changed;
4804 int err;
4805
4806 BT_DBG("request for %s", hdev->name);
4807
4808 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004809 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4810 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004811
4812 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004813 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4814 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004815
4816 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004817 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4818 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004819
4820 hci_dev_lock(hdev);
4821
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004822 /* If user space supports this command it is also expected to
4823 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4824 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004825 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004826
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004827 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004828 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004829 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004830 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004831 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004832 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004833 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004834 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004835 }
4836
4837 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4838 if (err < 0)
4839 goto unlock;
4840
4841 if (changed)
4842 err = new_settings(hdev, sk);
4843
4844unlock:
4845 hci_dev_unlock(hdev);
4846 return err;
4847}
4848
Johan Hedberg41edf162014-02-18 10:19:35 +02004849static bool irk_is_valid(struct mgmt_irk_info *irk)
4850{
4851 switch (irk->addr.type) {
4852 case BDADDR_LE_PUBLIC:
4853 return true;
4854
4855 case BDADDR_LE_RANDOM:
4856 /* Two most significant bits shall be set */
4857 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4858 return false;
4859 return true;
4860 }
4861
4862 return false;
4863}
4864
4865static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4866 u16 len)
4867{
4868 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004869 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4870 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004871 u16 irk_count, expected_len;
4872 int i, err;
4873
4874 BT_DBG("request for %s", hdev->name);
4875
4876 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004877 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4878 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004879
4880 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004881 if (irk_count > max_irk_count) {
4882 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004883 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4884 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004885 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004886
4887 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4888 if (expected_len != len) {
4889 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004890 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004891 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4892 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004893 }
4894
4895 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4896
4897 for (i = 0; i < irk_count; i++) {
4898 struct mgmt_irk_info *key = &cp->irks[i];
4899
4900 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004901 return mgmt_cmd_status(sk, hdev->id,
4902 MGMT_OP_LOAD_IRKS,
4903 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004904 }
4905
4906 hci_dev_lock(hdev);
4907
4908 hci_smp_irks_clear(hdev);
4909
4910 for (i = 0; i < irk_count; i++) {
4911 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004912
Johan Hedberg85813a72015-10-21 18:02:59 +03004913 hci_add_irk(hdev, &irk->addr.bdaddr,
4914 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004915 BDADDR_ANY);
4916 }
4917
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004918 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004919
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004920 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004921
4922 hci_dev_unlock(hdev);
4923
4924 return err;
4925}
4926
Johan Hedberg3f706b72013-01-20 14:27:16 +02004927static bool ltk_is_valid(struct mgmt_ltk_info *key)
4928{
4929 if (key->master != 0x00 && key->master != 0x01)
4930 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004931
4932 switch (key->addr.type) {
4933 case BDADDR_LE_PUBLIC:
4934 return true;
4935
4936 case BDADDR_LE_RANDOM:
4937 /* Two most significant bits shall be set */
4938 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4939 return false;
4940 return true;
4941 }
4942
4943 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004944}
4945
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004946static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004947 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004948{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004949 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004950 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4951 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004952 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004953 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004954
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004955 BT_DBG("request for %s", hdev->name);
4956
4957 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004958 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4959 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004960
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004961 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004962 if (key_count > max_key_count) {
4963 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004964 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004966 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004967
4968 expected_len = sizeof(*cp) + key_count *
4969 sizeof(struct mgmt_ltk_info);
4970 if (expected_len != len) {
4971 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004972 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004973 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4974 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004975 }
4976
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004977 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004978
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004979 for (i = 0; i < key_count; i++) {
4980 struct mgmt_ltk_info *key = &cp->keys[i];
4981
Johan Hedberg3f706b72013-01-20 14:27:16 +02004982 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004983 return mgmt_cmd_status(sk, hdev->id,
4984 MGMT_OP_LOAD_LONG_TERM_KEYS,
4985 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004986 }
4987
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004988 hci_dev_lock(hdev);
4989
4990 hci_smp_ltks_clear(hdev);
4991
4992 for (i = 0; i < key_count; i++) {
4993 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004994 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004995
Johan Hedberg61b43352014-05-29 19:36:53 +03004996 switch (key->type) {
4997 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004998 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004999 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005000 break;
5001 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005002 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005003 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005004 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005005 case MGMT_LTK_P256_UNAUTH:
5006 authenticated = 0x00;
5007 type = SMP_LTK_P256;
5008 break;
5009 case MGMT_LTK_P256_AUTH:
5010 authenticated = 0x01;
5011 type = SMP_LTK_P256;
5012 break;
5013 case MGMT_LTK_P256_DEBUG:
5014 authenticated = 0x00;
5015 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005016 default:
5017 continue;
5018 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005019
Johan Hedberg85813a72015-10-21 18:02:59 +03005020 hci_add_ltk(hdev, &key->addr.bdaddr,
5021 le_addr_type(key->addr.type), type, authenticated,
5022 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005023 }
5024
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005025 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005026 NULL, 0);
5027
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005028 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005029
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005030 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005031}
5032
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005033static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005034{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005035 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005036 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005037 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005038
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005039 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005040
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005041 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005042 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005043 rp.tx_power = conn->tx_power;
5044 rp.max_tx_power = conn->max_tx_power;
5045 } else {
5046 rp.rssi = HCI_RSSI_INVALID;
5047 rp.tx_power = HCI_TX_POWER_INVALID;
5048 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005049 }
5050
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005051 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5052 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005053
5054 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005055 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005056
5057 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005058}
5059
Marcel Holtmann1904a852015-01-11 13:50:44 -08005060static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5061 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005062{
5063 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005064 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005065 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005066 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005067 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005068
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005069 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005070
5071 hci_dev_lock(hdev);
5072
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005073 /* Commands sent in request are either Read RSSI or Read Transmit Power
5074 * Level so we check which one was last sent to retrieve connection
5075 * handle. Both commands have handle as first parameter so it's safe to
5076 * cast data on the same command struct.
5077 *
5078 * First command sent is always Read RSSI and we fail only if it fails.
5079 * In other case we simply override error to indicate success as we
5080 * already remembered if TX power value is actually valid.
5081 */
5082 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5083 if (!cp) {
5084 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005085 status = MGMT_STATUS_SUCCESS;
5086 } else {
5087 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005088 }
5089
5090 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005091 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005092 goto unlock;
5093 }
5094
5095 handle = __le16_to_cpu(cp->handle);
5096 conn = hci_conn_hash_lookup_handle(hdev, handle);
5097 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005098 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005099 goto unlock;
5100 }
5101
Johan Hedberg333ae952015-03-17 13:48:47 +02005102 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005103 if (!cmd)
5104 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005105
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005106 cmd->cmd_complete(cmd, status);
5107 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005108
5109unlock:
5110 hci_dev_unlock(hdev);
5111}
5112
5113static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5114 u16 len)
5115{
5116 struct mgmt_cp_get_conn_info *cp = data;
5117 struct mgmt_rp_get_conn_info rp;
5118 struct hci_conn *conn;
5119 unsigned long conn_info_age;
5120 int err = 0;
5121
5122 BT_DBG("%s", hdev->name);
5123
5124 memset(&rp, 0, sizeof(rp));
5125 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5126 rp.addr.type = cp->addr.type;
5127
5128 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005129 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5130 MGMT_STATUS_INVALID_PARAMS,
5131 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005132
5133 hci_dev_lock(hdev);
5134
5135 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005136 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5137 MGMT_STATUS_NOT_POWERED, &rp,
5138 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005139 goto unlock;
5140 }
5141
5142 if (cp->addr.type == BDADDR_BREDR)
5143 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5144 &cp->addr.bdaddr);
5145 else
5146 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5147
5148 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005149 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5150 MGMT_STATUS_NOT_CONNECTED, &rp,
5151 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005152 goto unlock;
5153 }
5154
Johan Hedberg333ae952015-03-17 13:48:47 +02005155 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005156 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5157 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005158 goto unlock;
5159 }
5160
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005161 /* To avoid client trying to guess when to poll again for information we
5162 * calculate conn info age as random value between min/max set in hdev.
5163 */
5164 conn_info_age = hdev->conn_info_min_age +
5165 prandom_u32_max(hdev->conn_info_max_age -
5166 hdev->conn_info_min_age);
5167
5168 /* Query controller to refresh cached values if they are too old or were
5169 * never read.
5170 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005171 if (time_after(jiffies, conn->conn_info_timestamp +
5172 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005173 !conn->conn_info_timestamp) {
5174 struct hci_request req;
5175 struct hci_cp_read_tx_power req_txp_cp;
5176 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005177 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005178
5179 hci_req_init(&req, hdev);
5180 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5181 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5182 &req_rssi_cp);
5183
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005184 /* For LE links TX power does not change thus we don't need to
5185 * query for it once value is known.
5186 */
5187 if (!bdaddr_type_is_le(cp->addr.type) ||
5188 conn->tx_power == HCI_TX_POWER_INVALID) {
5189 req_txp_cp.handle = cpu_to_le16(conn->handle);
5190 req_txp_cp.type = 0x00;
5191 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5192 sizeof(req_txp_cp), &req_txp_cp);
5193 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005194
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005195 /* Max TX power needs to be read only once per connection */
5196 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5197 req_txp_cp.handle = cpu_to_le16(conn->handle);
5198 req_txp_cp.type = 0x01;
5199 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5200 sizeof(req_txp_cp), &req_txp_cp);
5201 }
5202
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005203 err = hci_req_run(&req, conn_info_refresh_complete);
5204 if (err < 0)
5205 goto unlock;
5206
5207 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5208 data, len);
5209 if (!cmd) {
5210 err = -ENOMEM;
5211 goto unlock;
5212 }
5213
5214 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005215 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005216 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005217
5218 conn->conn_info_timestamp = jiffies;
5219 } else {
5220 /* Cache is valid, just reply with values cached in hci_conn */
5221 rp.rssi = conn->rssi;
5222 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005223 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005224
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005225 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5226 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005227 }
5228
5229unlock:
5230 hci_dev_unlock(hdev);
5231 return err;
5232}
5233
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005234static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005235{
5236 struct hci_conn *conn = cmd->user_data;
5237 struct mgmt_rp_get_clock_info rp;
5238 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005239 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005240
5241 memset(&rp, 0, sizeof(rp));
5242 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5243
5244 if (status)
5245 goto complete;
5246
5247 hdev = hci_dev_get(cmd->index);
5248 if (hdev) {
5249 rp.local_clock = cpu_to_le32(hdev->clock);
5250 hci_dev_put(hdev);
5251 }
5252
5253 if (conn) {
5254 rp.piconet_clock = cpu_to_le32(conn->clock);
5255 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5256 }
5257
5258complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005259 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5260 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005261
5262 if (conn) {
5263 hci_conn_drop(conn);
5264 hci_conn_put(conn);
5265 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005266
5267 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005268}
5269
Marcel Holtmann1904a852015-01-11 13:50:44 -08005270static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005271{
Johan Hedberg95868422014-06-28 17:54:07 +03005272 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005273 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005274 struct hci_conn *conn;
5275
5276 BT_DBG("%s status %u", hdev->name, status);
5277
5278 hci_dev_lock(hdev);
5279
5280 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5281 if (!hci_cp)
5282 goto unlock;
5283
5284 if (hci_cp->which) {
5285 u16 handle = __le16_to_cpu(hci_cp->handle);
5286 conn = hci_conn_hash_lookup_handle(hdev, handle);
5287 } else {
5288 conn = NULL;
5289 }
5290
Johan Hedberg333ae952015-03-17 13:48:47 +02005291 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005292 if (!cmd)
5293 goto unlock;
5294
Johan Hedberg69487372014-12-05 13:36:07 +02005295 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005296 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005297
5298unlock:
5299 hci_dev_unlock(hdev);
5300}
5301
5302static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5303 u16 len)
5304{
5305 struct mgmt_cp_get_clock_info *cp = data;
5306 struct mgmt_rp_get_clock_info rp;
5307 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005308 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005309 struct hci_request req;
5310 struct hci_conn *conn;
5311 int err;
5312
5313 BT_DBG("%s", hdev->name);
5314
5315 memset(&rp, 0, sizeof(rp));
5316 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5317 rp.addr.type = cp->addr.type;
5318
5319 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005320 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5321 MGMT_STATUS_INVALID_PARAMS,
5322 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005323
5324 hci_dev_lock(hdev);
5325
5326 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005327 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5328 MGMT_STATUS_NOT_POWERED, &rp,
5329 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005330 goto unlock;
5331 }
5332
5333 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5334 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5335 &cp->addr.bdaddr);
5336 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005337 err = mgmt_cmd_complete(sk, hdev->id,
5338 MGMT_OP_GET_CLOCK_INFO,
5339 MGMT_STATUS_NOT_CONNECTED,
5340 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005341 goto unlock;
5342 }
5343 } else {
5344 conn = NULL;
5345 }
5346
5347 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5348 if (!cmd) {
5349 err = -ENOMEM;
5350 goto unlock;
5351 }
5352
Johan Hedberg69487372014-12-05 13:36:07 +02005353 cmd->cmd_complete = clock_info_cmd_complete;
5354
Johan Hedberg95868422014-06-28 17:54:07 +03005355 hci_req_init(&req, hdev);
5356
5357 memset(&hci_cp, 0, sizeof(hci_cp));
5358 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5359
5360 if (conn) {
5361 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005362 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005363
5364 hci_cp.handle = cpu_to_le16(conn->handle);
5365 hci_cp.which = 0x01; /* Piconet clock */
5366 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5367 }
5368
5369 err = hci_req_run(&req, get_clock_info_complete);
5370 if (err < 0)
5371 mgmt_pending_remove(cmd);
5372
5373unlock:
5374 hci_dev_unlock(hdev);
5375 return err;
5376}
5377
Johan Hedberg5a154e62014-12-19 22:26:02 +02005378static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5379{
5380 struct hci_conn *conn;
5381
5382 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5383 if (!conn)
5384 return false;
5385
5386 if (conn->dst_type != type)
5387 return false;
5388
5389 if (conn->state != BT_CONNECTED)
5390 return false;
5391
5392 return true;
5393}
5394
5395/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005396static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005397 u8 addr_type, u8 auto_connect)
5398{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005399 struct hci_conn_params *params;
5400
5401 params = hci_conn_params_add(hdev, addr, addr_type);
5402 if (!params)
5403 return -EIO;
5404
5405 if (params->auto_connect == auto_connect)
5406 return 0;
5407
5408 list_del_init(&params->action);
5409
5410 switch (auto_connect) {
5411 case HCI_AUTO_CONN_DISABLED:
5412 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005413 /* If auto connect is being disabled when we're trying to
5414 * connect to device, keep connecting.
5415 */
5416 if (params->explicit_connect)
5417 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005418 break;
5419 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005420 if (params->explicit_connect)
5421 list_add(&params->action, &hdev->pend_le_conns);
5422 else
5423 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005424 break;
5425 case HCI_AUTO_CONN_DIRECT:
5426 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005427 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005428 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005429 break;
5430 }
5431
5432 params->auto_connect = auto_connect;
5433
5434 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5435 auto_connect);
5436
5437 return 0;
5438}
5439
Marcel Holtmann8afef092014-06-29 22:28:34 +02005440static void device_added(struct sock *sk, struct hci_dev *hdev,
5441 bdaddr_t *bdaddr, u8 type, u8 action)
5442{
5443 struct mgmt_ev_device_added ev;
5444
5445 bacpy(&ev.addr.bdaddr, bdaddr);
5446 ev.addr.type = type;
5447 ev.action = action;
5448
5449 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5450}
5451
Marcel Holtmann2faade52014-06-29 19:44:03 +02005452static int add_device(struct sock *sk, struct hci_dev *hdev,
5453 void *data, u16 len)
5454{
5455 struct mgmt_cp_add_device *cp = data;
5456 u8 auto_conn, addr_type;
5457 int err;
5458
5459 BT_DBG("%s", hdev->name);
5460
Johan Hedberg66593582014-07-09 12:59:14 +03005461 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005462 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005463 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5464 MGMT_STATUS_INVALID_PARAMS,
5465 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005466
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005467 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005468 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5469 MGMT_STATUS_INVALID_PARAMS,
5470 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005471
5472 hci_dev_lock(hdev);
5473
Johan Hedberg66593582014-07-09 12:59:14 +03005474 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005475 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005476 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005477 err = mgmt_cmd_complete(sk, hdev->id,
5478 MGMT_OP_ADD_DEVICE,
5479 MGMT_STATUS_INVALID_PARAMS,
5480 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005481 goto unlock;
5482 }
5483
5484 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5485 cp->addr.type);
5486 if (err)
5487 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005488
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005489 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005490
Johan Hedberg66593582014-07-09 12:59:14 +03005491 goto added;
5492 }
5493
Johan Hedberg85813a72015-10-21 18:02:59 +03005494 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005495
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005496 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005497 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005498 else if (cp->action == 0x01)
5499 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005500 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005501 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005502
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005503 /* Kernel internally uses conn_params with resolvable private
5504 * address, but Add Device allows only identity addresses.
5505 * Make sure it is enforced before calling
5506 * hci_conn_params_lookup.
5507 */
5508 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005509 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5510 MGMT_STATUS_INVALID_PARAMS,
5511 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005512 goto unlock;
5513 }
5514
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005515 /* If the connection parameters don't exist for this device,
5516 * they will be created and configured with defaults.
5517 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005518 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005519 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005520 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5521 MGMT_STATUS_FAILED, &cp->addr,
5522 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005523 goto unlock;
5524 }
5525
Johan Hedberg51d7a942015-11-11 08:11:18 +02005526 hci_update_background_scan(hdev);
5527
Johan Hedberg66593582014-07-09 12:59:14 +03005528added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005529 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5530
Johan Hedberg51d7a942015-11-11 08:11:18 +02005531 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5532 MGMT_STATUS_SUCCESS, &cp->addr,
5533 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005534
5535unlock:
5536 hci_dev_unlock(hdev);
5537 return err;
5538}
5539
Marcel Holtmann8afef092014-06-29 22:28:34 +02005540static void device_removed(struct sock *sk, struct hci_dev *hdev,
5541 bdaddr_t *bdaddr, u8 type)
5542{
5543 struct mgmt_ev_device_removed ev;
5544
5545 bacpy(&ev.addr.bdaddr, bdaddr);
5546 ev.addr.type = type;
5547
5548 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5549}
5550
Marcel Holtmann2faade52014-06-29 19:44:03 +02005551static int remove_device(struct sock *sk, struct hci_dev *hdev,
5552 void *data, u16 len)
5553{
5554 struct mgmt_cp_remove_device *cp = data;
5555 int err;
5556
5557 BT_DBG("%s", hdev->name);
5558
5559 hci_dev_lock(hdev);
5560
5561 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005562 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005563 u8 addr_type;
5564
Johan Hedberg66593582014-07-09 12:59:14 +03005565 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005566 err = mgmt_cmd_complete(sk, hdev->id,
5567 MGMT_OP_REMOVE_DEVICE,
5568 MGMT_STATUS_INVALID_PARAMS,
5569 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005570 goto unlock;
5571 }
5572
Johan Hedberg66593582014-07-09 12:59:14 +03005573 if (cp->addr.type == BDADDR_BREDR) {
5574 err = hci_bdaddr_list_del(&hdev->whitelist,
5575 &cp->addr.bdaddr,
5576 cp->addr.type);
5577 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005578 err = mgmt_cmd_complete(sk, hdev->id,
5579 MGMT_OP_REMOVE_DEVICE,
5580 MGMT_STATUS_INVALID_PARAMS,
5581 &cp->addr,
5582 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005583 goto unlock;
5584 }
5585
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005586 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005587
Johan Hedberg66593582014-07-09 12:59:14 +03005588 device_removed(sk, hdev, &cp->addr.bdaddr,
5589 cp->addr.type);
5590 goto complete;
5591 }
5592
Johan Hedberg85813a72015-10-21 18:02:59 +03005593 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005594
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005595 /* Kernel internally uses conn_params with resolvable private
5596 * address, but Remove Device allows only identity addresses.
5597 * Make sure it is enforced before calling
5598 * hci_conn_params_lookup.
5599 */
5600 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005601 err = mgmt_cmd_complete(sk, hdev->id,
5602 MGMT_OP_REMOVE_DEVICE,
5603 MGMT_STATUS_INVALID_PARAMS,
5604 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005605 goto unlock;
5606 }
5607
Johan Hedbergc71593d2014-07-02 17:37:28 +03005608 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5609 addr_type);
5610 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005611 err = mgmt_cmd_complete(sk, hdev->id,
5612 MGMT_OP_REMOVE_DEVICE,
5613 MGMT_STATUS_INVALID_PARAMS,
5614 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005615 goto unlock;
5616 }
5617
Johan Hedberg679d2b62015-10-16 10:07:52 +03005618 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5619 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005620 err = mgmt_cmd_complete(sk, hdev->id,
5621 MGMT_OP_REMOVE_DEVICE,
5622 MGMT_STATUS_INVALID_PARAMS,
5623 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005624 goto unlock;
5625 }
5626
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005627 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005628 list_del(&params->list);
5629 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005630 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005631
5632 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005633 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005634 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005635 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005636
Marcel Holtmann2faade52014-06-29 19:44:03 +02005637 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005638 err = mgmt_cmd_complete(sk, hdev->id,
5639 MGMT_OP_REMOVE_DEVICE,
5640 MGMT_STATUS_INVALID_PARAMS,
5641 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005642 goto unlock;
5643 }
5644
Johan Hedberg66593582014-07-09 12:59:14 +03005645 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5646 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5647 list_del(&b->list);
5648 kfree(b);
5649 }
5650
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005651 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005652
Johan Hedberg19de0822014-07-06 13:06:51 +03005653 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5654 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5655 continue;
5656 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005657 if (p->explicit_connect) {
5658 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5659 continue;
5660 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005661 list_del(&p->action);
5662 list_del(&p->list);
5663 kfree(p);
5664 }
5665
5666 BT_DBG("All LE connection parameters were removed");
5667
Johan Hedberg51d7a942015-11-11 08:11:18 +02005668 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005669 }
5670
Johan Hedberg66593582014-07-09 12:59:14 +03005671complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005672 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5673 MGMT_STATUS_SUCCESS, &cp->addr,
5674 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005675unlock:
5676 hci_dev_unlock(hdev);
5677 return err;
5678}
5679
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005680static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5681 u16 len)
5682{
5683 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005684 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5685 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005686 u16 param_count, expected_len;
5687 int i;
5688
5689 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005690 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5691 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005692
5693 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005694 if (param_count > max_param_count) {
5695 BT_ERR("load_conn_param: too big param_count value %u",
5696 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005697 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5698 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005699 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005700
5701 expected_len = sizeof(*cp) + param_count *
5702 sizeof(struct mgmt_conn_param);
5703 if (expected_len != len) {
5704 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5705 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005706 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5707 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005708 }
5709
5710 BT_DBG("%s param_count %u", hdev->name, param_count);
5711
5712 hci_dev_lock(hdev);
5713
5714 hci_conn_params_clear_disabled(hdev);
5715
5716 for (i = 0; i < param_count; i++) {
5717 struct mgmt_conn_param *param = &cp->params[i];
5718 struct hci_conn_params *hci_param;
5719 u16 min, max, latency, timeout;
5720 u8 addr_type;
5721
5722 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5723 param->addr.type);
5724
5725 if (param->addr.type == BDADDR_LE_PUBLIC) {
5726 addr_type = ADDR_LE_DEV_PUBLIC;
5727 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5728 addr_type = ADDR_LE_DEV_RANDOM;
5729 } else {
5730 BT_ERR("Ignoring invalid connection parameters");
5731 continue;
5732 }
5733
5734 min = le16_to_cpu(param->min_interval);
5735 max = le16_to_cpu(param->max_interval);
5736 latency = le16_to_cpu(param->latency);
5737 timeout = le16_to_cpu(param->timeout);
5738
5739 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5740 min, max, latency, timeout);
5741
5742 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5743 BT_ERR("Ignoring invalid connection parameters");
5744 continue;
5745 }
5746
5747 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5748 addr_type);
5749 if (!hci_param) {
5750 BT_ERR("Failed to add connection parameters");
5751 continue;
5752 }
5753
5754 hci_param->conn_min_interval = min;
5755 hci_param->conn_max_interval = max;
5756 hci_param->conn_latency = latency;
5757 hci_param->supervision_timeout = timeout;
5758 }
5759
5760 hci_dev_unlock(hdev);
5761
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005762 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5763 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005764}
5765
Marcel Holtmanndbece372014-07-04 18:11:55 +02005766static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5767 void *data, u16 len)
5768{
5769 struct mgmt_cp_set_external_config *cp = data;
5770 bool changed;
5771 int err;
5772
5773 BT_DBG("%s", hdev->name);
5774
5775 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005776 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5777 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005778
5779 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005780 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5781 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005782
5783 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005784 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5785 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005786
5787 hci_dev_lock(hdev);
5788
5789 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005790 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005791 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005792 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005793
5794 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5795 if (err < 0)
5796 goto unlock;
5797
5798 if (!changed)
5799 goto unlock;
5800
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005801 err = new_options(hdev, sk);
5802
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005803 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005804 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005805
Marcel Holtmann516018a2015-03-13 02:11:04 -07005806 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005807 hci_dev_set_flag(hdev, HCI_CONFIG);
5808 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005809
5810 queue_work(hdev->req_workqueue, &hdev->power_on);
5811 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005812 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005813 mgmt_index_added(hdev);
5814 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005815 }
5816
5817unlock:
5818 hci_dev_unlock(hdev);
5819 return err;
5820}
5821
Marcel Holtmann9713c172014-07-06 12:11:15 +02005822static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5823 void *data, u16 len)
5824{
5825 struct mgmt_cp_set_public_address *cp = data;
5826 bool changed;
5827 int err;
5828
5829 BT_DBG("%s", hdev->name);
5830
5831 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005832 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5833 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005834
5835 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005836 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5837 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005838
5839 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005840 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5841 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005842
5843 hci_dev_lock(hdev);
5844
5845 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5846 bacpy(&hdev->public_addr, &cp->bdaddr);
5847
5848 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5849 if (err < 0)
5850 goto unlock;
5851
5852 if (!changed)
5853 goto unlock;
5854
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005855 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005856 err = new_options(hdev, sk);
5857
5858 if (is_configured(hdev)) {
5859 mgmt_index_removed(hdev);
5860
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005861 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005862
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005863 hci_dev_set_flag(hdev, HCI_CONFIG);
5864 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005865
5866 queue_work(hdev->req_workqueue, &hdev->power_on);
5867 }
5868
5869unlock:
5870 hci_dev_unlock(hdev);
5871 return err;
5872}
5873
Marcel Holtmannbea41602015-03-14 22:43:17 -07005874static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5875 u8 data_len)
5876{
5877 eir[eir_len++] = sizeof(type) + data_len;
5878 eir[eir_len++] = type;
5879 memcpy(&eir[eir_len], data, data_len);
5880 eir_len += data_len;
5881
5882 return eir_len;
5883}
5884
Johan Hedberg40f66c02015-04-07 21:52:22 +03005885static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5886 u16 opcode, struct sk_buff *skb)
5887{
5888 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5889 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5890 u8 *h192, *r192, *h256, *r256;
5891 struct mgmt_pending_cmd *cmd;
5892 u16 eir_len;
5893 int err;
5894
5895 BT_DBG("%s status %u", hdev->name, status);
5896
5897 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5898 if (!cmd)
5899 return;
5900
5901 mgmt_cp = cmd->param;
5902
5903 if (status) {
5904 status = mgmt_status(status);
5905 eir_len = 0;
5906
5907 h192 = NULL;
5908 r192 = NULL;
5909 h256 = NULL;
5910 r256 = NULL;
5911 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5912 struct hci_rp_read_local_oob_data *rp;
5913
5914 if (skb->len != sizeof(*rp)) {
5915 status = MGMT_STATUS_FAILED;
5916 eir_len = 0;
5917 } else {
5918 status = MGMT_STATUS_SUCCESS;
5919 rp = (void *)skb->data;
5920
5921 eir_len = 5 + 18 + 18;
5922 h192 = rp->hash;
5923 r192 = rp->rand;
5924 h256 = NULL;
5925 r256 = NULL;
5926 }
5927 } else {
5928 struct hci_rp_read_local_oob_ext_data *rp;
5929
5930 if (skb->len != sizeof(*rp)) {
5931 status = MGMT_STATUS_FAILED;
5932 eir_len = 0;
5933 } else {
5934 status = MGMT_STATUS_SUCCESS;
5935 rp = (void *)skb->data;
5936
5937 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5938 eir_len = 5 + 18 + 18;
5939 h192 = NULL;
5940 r192 = NULL;
5941 } else {
5942 eir_len = 5 + 18 + 18 + 18 + 18;
5943 h192 = rp->hash192;
5944 r192 = rp->rand192;
5945 }
5946
5947 h256 = rp->hash256;
5948 r256 = rp->rand256;
5949 }
5950 }
5951
5952 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5953 if (!mgmt_rp)
5954 goto done;
5955
5956 if (status)
5957 goto send_rsp;
5958
5959 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5960 hdev->dev_class, 3);
5961
5962 if (h192 && r192) {
5963 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5964 EIR_SSP_HASH_C192, h192, 16);
5965 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5966 EIR_SSP_RAND_R192, r192, 16);
5967 }
5968
5969 if (h256 && r256) {
5970 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5971 EIR_SSP_HASH_C256, h256, 16);
5972 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5973 EIR_SSP_RAND_R256, r256, 16);
5974 }
5975
5976send_rsp:
5977 mgmt_rp->type = mgmt_cp->type;
5978 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5979
5980 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5981 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5982 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5983 if (err < 0 || status)
5984 goto done;
5985
5986 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5987
5988 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5989 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5990 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5991done:
5992 kfree(mgmt_rp);
5993 mgmt_pending_remove(cmd);
5994}
5995
5996static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5997 struct mgmt_cp_read_local_oob_ext_data *cp)
5998{
5999 struct mgmt_pending_cmd *cmd;
6000 struct hci_request req;
6001 int err;
6002
6003 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6004 cp, sizeof(*cp));
6005 if (!cmd)
6006 return -ENOMEM;
6007
6008 hci_req_init(&req, hdev);
6009
6010 if (bredr_sc_enabled(hdev))
6011 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6012 else
6013 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6014
6015 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6016 if (err < 0) {
6017 mgmt_pending_remove(cmd);
6018 return err;
6019 }
6020
6021 return 0;
6022}
6023
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006024static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6025 void *data, u16 data_len)
6026{
6027 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6028 struct mgmt_rp_read_local_oob_ext_data *rp;
6029 size_t rp_len;
6030 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006031 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006032 int err;
6033
6034 BT_DBG("%s", hdev->name);
6035
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006036 if (hdev_is_powered(hdev)) {
6037 switch (cp->type) {
6038 case BIT(BDADDR_BREDR):
6039 status = mgmt_bredr_support(hdev);
6040 if (status)
6041 eir_len = 0;
6042 else
6043 eir_len = 5;
6044 break;
6045 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6046 status = mgmt_le_support(hdev);
6047 if (status)
6048 eir_len = 0;
6049 else
6050 eir_len = 9 + 3 + 18 + 18 + 3;
6051 break;
6052 default:
6053 status = MGMT_STATUS_INVALID_PARAMS;
6054 eir_len = 0;
6055 break;
6056 }
6057 } else {
6058 status = MGMT_STATUS_NOT_POWERED;
6059 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006060 }
6061
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006062 rp_len = sizeof(*rp) + eir_len;
6063 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006064 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006065 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006066
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006067 if (status)
6068 goto complete;
6069
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006070 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006071
6072 eir_len = 0;
6073 switch (cp->type) {
6074 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006075 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6076 err = read_local_ssp_oob_req(hdev, sk, cp);
6077 hci_dev_unlock(hdev);
6078 if (!err)
6079 goto done;
6080
6081 status = MGMT_STATUS_FAILED;
6082 goto complete;
6083 } else {
6084 eir_len = eir_append_data(rp->eir, eir_len,
6085 EIR_CLASS_OF_DEV,
6086 hdev->dev_class, 3);
6087 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006088 break;
6089 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006090 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6091 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006092 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006093 status = MGMT_STATUS_FAILED;
6094 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006095 }
6096
Marcel Holtmanne2135682015-04-02 12:00:58 -07006097 /* This should return the active RPA, but since the RPA
6098 * is only programmed on demand, it is really hard to fill
6099 * this in at the moment. For now disallow retrieving
6100 * local out-of-band data when privacy is in use.
6101 *
6102 * Returning the identity address will not help here since
6103 * pairing happens before the identity resolving key is
6104 * known and thus the connection establishment happens
6105 * based on the RPA and not the identity address.
6106 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006107 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006108 hci_dev_unlock(hdev);
6109 status = MGMT_STATUS_REJECTED;
6110 goto complete;
6111 }
6112
6113 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6114 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6115 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6116 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006117 memcpy(addr, &hdev->static_addr, 6);
6118 addr[6] = 0x01;
6119 } else {
6120 memcpy(addr, &hdev->bdaddr, 6);
6121 addr[6] = 0x00;
6122 }
6123
6124 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6125 addr, sizeof(addr));
6126
6127 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6128 role = 0x02;
6129 else
6130 role = 0x01;
6131
6132 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6133 &role, sizeof(role));
6134
Marcel Holtmann5082a592015-03-16 12:39:00 -07006135 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6136 eir_len = eir_append_data(rp->eir, eir_len,
6137 EIR_LE_SC_CONFIRM,
6138 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006139
Marcel Holtmann5082a592015-03-16 12:39:00 -07006140 eir_len = eir_append_data(rp->eir, eir_len,
6141 EIR_LE_SC_RANDOM,
6142 rand, sizeof(rand));
6143 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006144
Johan Hedbergf2252572015-11-18 12:49:20 +02006145 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006146
6147 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6148 flags |= LE_AD_NO_BREDR;
6149
6150 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6151 &flags, sizeof(flags));
6152 break;
6153 }
6154
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006155 hci_dev_unlock(hdev);
6156
Marcel Holtmann72000df2015-03-16 16:11:21 -07006157 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6158
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006159 status = MGMT_STATUS_SUCCESS;
6160
6161complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006162 rp->type = cp->type;
6163 rp->eir_len = cpu_to_le16(eir_len);
6164
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006165 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006166 status, rp, sizeof(*rp) + eir_len);
6167 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006168 goto done;
6169
6170 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6171 rp, sizeof(*rp) + eir_len,
6172 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006173
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006174done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006175 kfree(rp);
6176
6177 return err;
6178}
6179
Arman Uguray089fa8c2015-03-25 18:53:45 -07006180static u32 get_supported_adv_flags(struct hci_dev *hdev)
6181{
6182 u32 flags = 0;
6183
6184 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6185 flags |= MGMT_ADV_FLAG_DISCOV;
6186 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6187 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
6188
6189 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
6190 flags |= MGMT_ADV_FLAG_TX_POWER;
6191
6192 return flags;
6193}
6194
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006195static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6196 void *data, u16 data_len)
6197{
6198 struct mgmt_rp_read_adv_features *rp;
6199 size_t rp_len;
Florian Grandel286e0c82015-06-18 03:16:38 +02006200 int err, i;
Arman Uguray24b4f382015-03-23 15:57:12 -07006201 bool instance;
Florian Grandel286e0c82015-06-18 03:16:38 +02006202 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006203 u32 supported_flags;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006204
6205 BT_DBG("%s", hdev->name);
6206
Arman Uguray089fa8c2015-03-25 18:53:45 -07006207 if (!lmp_le_capable(hdev))
6208 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6209 MGMT_STATUS_REJECTED);
6210
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006211 hci_dev_lock(hdev);
6212
6213 rp_len = sizeof(*rp);
Arman Uguray24b4f382015-03-23 15:57:12 -07006214
Arman Uguray24b4f382015-03-23 15:57:12 -07006215 instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
6216 if (instance)
Florian Grandel286e0c82015-06-18 03:16:38 +02006217 rp_len += hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006218
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006219 rp = kmalloc(rp_len, GFP_ATOMIC);
6220 if (!rp) {
6221 hci_dev_unlock(hdev);
6222 return -ENOMEM;
6223 }
6224
Arman Uguray089fa8c2015-03-25 18:53:45 -07006225 supported_flags = get_supported_adv_flags(hdev);
6226
6227 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006228 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6229 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006230 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Arman Uguray24b4f382015-03-23 15:57:12 -07006231
Arman Uguray24b4f382015-03-23 15:57:12 -07006232 if (instance) {
Florian Grandel286e0c82015-06-18 03:16:38 +02006233 i = 0;
6234 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6235 if (i >= hdev->adv_instance_cnt)
6236 break;
6237
6238 rp->instance[i] = adv_instance->instance;
6239 i++;
6240 }
6241 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006242 } else {
6243 rp->num_instances = 0;
6244 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006245
6246 hci_dev_unlock(hdev);
6247
6248 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6249 MGMT_STATUS_SUCCESS, rp, rp_len);
6250
6251 kfree(rp);
6252
6253 return err;
6254}
6255
Arman Uguray4117ed72015-03-23 15:57:14 -07006256static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006257 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006258{
Arman Uguray4117ed72015-03-23 15:57:14 -07006259 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006260 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07006261 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07006262 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07006263
Marcel Holtmann31a32482015-11-19 16:16:42 +01006264 if (is_adv_data) {
6265 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6266 MGMT_ADV_FLAG_LIMITED_DISCOV |
6267 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
6268 flags_managed = true;
6269 max_len -= 3;
6270 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006271
Marcel Holtmann31a32482015-11-19 16:16:42 +01006272 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
6273 tx_power_managed = true;
6274 max_len -= 3;
6275 }
Arman Uguray5507e352015-03-25 18:53:44 -07006276 }
6277
Arman Uguray4117ed72015-03-23 15:57:14 -07006278 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006279 return false;
6280
Arman Uguray4117ed72015-03-23 15:57:14 -07006281 /* Make sure that the data is correctly formatted. */
6282 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6283 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006284
Arman Ugurayb44133f2015-03-25 18:53:41 -07006285 if (flags_managed && data[i + 1] == EIR_FLAGS)
6286 return false;
6287
Arman Uguray5507e352015-03-25 18:53:44 -07006288 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
6289 return false;
6290
Arman Uguray24b4f382015-03-23 15:57:12 -07006291 /* If the current field length would exceed the total data
6292 * length, then it's invalid.
6293 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006294 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006295 return false;
6296 }
6297
6298 return true;
6299}
6300
Arman Uguray24b4f382015-03-23 15:57:12 -07006301static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6302 u16 opcode)
6303{
6304 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006305 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006306 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006307 struct adv_info *adv_instance, *n;
6308 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006309
6310 BT_DBG("status %d", status);
6311
6312 hci_dev_lock(hdev);
6313
6314 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6315
Florian Grandelfffd38b2015-06-18 03:16:47 +02006316 if (status)
Arman Uguray24b4f382015-03-23 15:57:12 -07006317 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006318
6319 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6320 if (!adv_instance->pending)
6321 continue;
6322
6323 if (!status) {
6324 adv_instance->pending = false;
6325 continue;
6326 }
6327
6328 instance = adv_instance->instance;
6329
6330 if (hdev->cur_adv_instance == instance)
6331 cancel_adv_timeout(hdev);
6332
6333 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006334 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006335 }
6336
6337 if (!cmd)
6338 goto unlock;
6339
Florian Grandelfffd38b2015-06-18 03:16:47 +02006340 cp = cmd->param;
6341 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006342
6343 if (status)
6344 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6345 mgmt_status(status));
6346 else
6347 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6348 mgmt_status(status), &rp, sizeof(rp));
6349
6350 mgmt_pending_remove(cmd);
6351
6352unlock:
6353 hci_dev_unlock(hdev);
6354}
6355
6356static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6357 void *data, u16 data_len)
6358{
6359 struct mgmt_cp_add_advertising *cp = data;
6360 struct mgmt_rp_add_advertising rp;
6361 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006362 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006363 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006364 u16 timeout, duration;
6365 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6366 u8 schedule_instance = 0;
6367 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006368 int err;
6369 struct mgmt_pending_cmd *cmd;
6370 struct hci_request req;
6371
6372 BT_DBG("%s", hdev->name);
6373
6374 status = mgmt_le_support(hdev);
6375 if (status)
6376 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6377 status);
6378
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006379 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6380 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6381 MGMT_STATUS_INVALID_PARAMS);
6382
Arman Uguray24b4f382015-03-23 15:57:12 -07006383 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006384 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006385 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006386
Florian Grandelfffd38b2015-06-18 03:16:47 +02006387 /* The current implementation only supports a subset of the specified
6388 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006389 */
6390 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006391 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006392 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6393 MGMT_STATUS_INVALID_PARAMS);
6394
6395 hci_dev_lock(hdev);
6396
Arman Uguray912098a2015-03-23 15:57:15 -07006397 if (timeout && !hdev_is_powered(hdev)) {
6398 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6399 MGMT_STATUS_REJECTED);
6400 goto unlock;
6401 }
6402
Arman Uguray24b4f382015-03-23 15:57:12 -07006403 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006404 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006405 pending_find(MGMT_OP_SET_LE, hdev)) {
6406 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6407 MGMT_STATUS_BUSY);
6408 goto unlock;
6409 }
6410
Arman Ugurayb44133f2015-03-25 18:53:41 -07006411 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006412 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006413 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006414 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6415 MGMT_STATUS_INVALID_PARAMS);
6416 goto unlock;
6417 }
6418
Florian Grandelfffd38b2015-06-18 03:16:47 +02006419 err = hci_add_adv_instance(hdev, cp->instance, flags,
6420 cp->adv_data_len, cp->data,
6421 cp->scan_rsp_len,
6422 cp->data + cp->adv_data_len,
6423 timeout, duration);
6424 if (err < 0) {
6425 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6426 MGMT_STATUS_FAILED);
6427 goto unlock;
6428 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006429
Florian Grandelfffd38b2015-06-18 03:16:47 +02006430 /* Only trigger an advertising added event if a new instance was
6431 * actually added.
6432 */
6433 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006434 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006435
Florian Grandelfffd38b2015-06-18 03:16:47 +02006436 hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
Arman Uguray24b4f382015-03-23 15:57:12 -07006437
Florian Grandelfffd38b2015-06-18 03:16:47 +02006438 if (hdev->cur_adv_instance == cp->instance) {
6439 /* If the currently advertised instance is being changed then
6440 * cancel the current advertising and schedule the next
6441 * instance. If there is only one instance then the overridden
6442 * advertising data will be visible right away.
6443 */
6444 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006445
Florian Grandelfffd38b2015-06-18 03:16:47 +02006446 next_instance = hci_get_next_instance(hdev, cp->instance);
6447 if (next_instance)
6448 schedule_instance = next_instance->instance;
6449 } else if (!hdev->adv_instance_timeout) {
6450 /* Immediately advertise the new instance if no other
6451 * instance is currently being advertised.
6452 */
6453 schedule_instance = cp->instance;
6454 }
Arman Uguray912098a2015-03-23 15:57:15 -07006455
Florian Grandelfffd38b2015-06-18 03:16:47 +02006456 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6457 * there is no instance to be advertised then we have no HCI
6458 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006459 */
6460 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006461 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6462 !schedule_instance) {
6463 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006464 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6465 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6466 goto unlock;
6467 }
6468
6469 /* We're good to go, update advertising data, parameters, and start
6470 * advertising.
6471 */
6472 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6473 data_len);
6474 if (!cmd) {
6475 err = -ENOMEM;
6476 goto unlock;
6477 }
6478
6479 hci_req_init(&req, hdev);
6480
Johan Hedbergf2252572015-11-18 12:49:20 +02006481 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006482
Florian Grandelfffd38b2015-06-18 03:16:47 +02006483 if (!err)
6484 err = hci_req_run(&req, add_advertising_complete);
6485
Arman Uguray24b4f382015-03-23 15:57:12 -07006486 if (err < 0)
6487 mgmt_pending_remove(cmd);
6488
6489unlock:
6490 hci_dev_unlock(hdev);
6491
6492 return err;
6493}
6494
Arman Ugurayda9293352015-03-23 15:57:13 -07006495static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6496 u16 opcode)
6497{
6498 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006499 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006500 struct mgmt_rp_remove_advertising rp;
6501
6502 BT_DBG("status %d", status);
6503
6504 hci_dev_lock(hdev);
6505
6506 /* A failure status here only means that we failed to disable
6507 * advertising. Otherwise, the advertising instance has been removed,
6508 * so report success.
6509 */
6510 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6511 if (!cmd)
6512 goto unlock;
6513
Florian Grandel01948332015-06-18 03:16:48 +02006514 cp = cmd->param;
6515 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006516
6517 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6518 &rp, sizeof(rp));
6519 mgmt_pending_remove(cmd);
6520
6521unlock:
6522 hci_dev_unlock(hdev);
6523}
6524
6525static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6526 void *data, u16 data_len)
6527{
6528 struct mgmt_cp_remove_advertising *cp = data;
6529 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006530 struct mgmt_pending_cmd *cmd;
6531 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006532 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006533
6534 BT_DBG("%s", hdev->name);
6535
Arman Ugurayda9293352015-03-23 15:57:13 -07006536 hci_dev_lock(hdev);
6537
Johan Hedberg952497b2015-06-18 21:05:31 +03006538 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006539 err = mgmt_cmd_status(sk, hdev->id,
6540 MGMT_OP_REMOVE_ADVERTISING,
6541 MGMT_STATUS_INVALID_PARAMS);
6542 goto unlock;
6543 }
6544
Arman Ugurayda9293352015-03-23 15:57:13 -07006545 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6546 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6547 pending_find(MGMT_OP_SET_LE, hdev)) {
6548 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6549 MGMT_STATUS_BUSY);
6550 goto unlock;
6551 }
6552
6553 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
6554 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6555 MGMT_STATUS_INVALID_PARAMS);
6556 goto unlock;
6557 }
6558
Florian Grandel01948332015-06-18 03:16:48 +02006559 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006560
Johan Hedbergf2252572015-11-18 12:49:20 +02006561 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006562
Florian Grandel01948332015-06-18 03:16:48 +02006563 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006564 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006565
Florian Grandel01948332015-06-18 03:16:48 +02006566 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6567 * flag is set or the device isn't powered then we have no HCI
6568 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006569 */
Florian Grandel01948332015-06-18 03:16:48 +02006570 if (skb_queue_empty(&req.cmd_q) ||
6571 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006572 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006573 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006574 err = mgmt_cmd_complete(sk, hdev->id,
6575 MGMT_OP_REMOVE_ADVERTISING,
6576 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6577 goto unlock;
6578 }
6579
6580 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6581 data_len);
6582 if (!cmd) {
6583 err = -ENOMEM;
6584 goto unlock;
6585 }
6586
Arman Ugurayda9293352015-03-23 15:57:13 -07006587 err = hci_req_run(&req, remove_advertising_complete);
6588 if (err < 0)
6589 mgmt_pending_remove(cmd);
6590
6591unlock:
6592 hci_dev_unlock(hdev);
6593
6594 return err;
6595}
6596
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006597static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6598{
6599 u8 max_len = HCI_MAX_AD_LENGTH;
6600
6601 if (is_adv_data) {
6602 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6603 MGMT_ADV_FLAG_LIMITED_DISCOV |
6604 MGMT_ADV_FLAG_MANAGED_FLAGS))
6605 max_len -= 3;
6606
6607 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6608 max_len -= 3;
6609 }
6610
6611 return max_len;
6612}
6613
6614static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6615 void *data, u16 data_len)
6616{
6617 struct mgmt_cp_get_adv_size_info *cp = data;
6618 struct mgmt_rp_get_adv_size_info rp;
6619 u32 flags, supported_flags;
6620 int err;
6621
6622 BT_DBG("%s", hdev->name);
6623
6624 if (!lmp_le_capable(hdev))
6625 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6626 MGMT_STATUS_REJECTED);
6627
6628 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6629 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6630 MGMT_STATUS_INVALID_PARAMS);
6631
6632 flags = __le32_to_cpu(cp->flags);
6633
6634 /* The current implementation only supports a subset of the specified
6635 * flags.
6636 */
6637 supported_flags = get_supported_adv_flags(hdev);
6638 if (flags & ~supported_flags)
6639 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6640 MGMT_STATUS_INVALID_PARAMS);
6641
6642 rp.instance = cp->instance;
6643 rp.flags = cp->flags;
6644 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6645 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6646
6647 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6648 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6649
6650 return err;
6651}
6652
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006653static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006654 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006655 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006656 HCI_MGMT_NO_HDEV |
6657 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006658 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006659 HCI_MGMT_NO_HDEV |
6660 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006661 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006662 HCI_MGMT_NO_HDEV |
6663 HCI_MGMT_UNTRUSTED },
6664 { read_controller_info, MGMT_READ_INFO_SIZE,
6665 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006666 { set_powered, MGMT_SETTING_SIZE },
6667 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6668 { set_connectable, MGMT_SETTING_SIZE },
6669 { set_fast_connectable, MGMT_SETTING_SIZE },
6670 { set_bondable, MGMT_SETTING_SIZE },
6671 { set_link_security, MGMT_SETTING_SIZE },
6672 { set_ssp, MGMT_SETTING_SIZE },
6673 { set_hs, MGMT_SETTING_SIZE },
6674 { set_le, MGMT_SETTING_SIZE },
6675 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6676 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6677 { add_uuid, MGMT_ADD_UUID_SIZE },
6678 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006679 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6680 HCI_MGMT_VAR_LEN },
6681 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6682 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006683 { disconnect, MGMT_DISCONNECT_SIZE },
6684 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6685 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6686 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6687 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6688 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6689 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6690 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6691 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6692 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6693 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6694 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006695 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6696 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6697 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006698 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6699 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6700 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6701 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6702 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6703 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6704 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6705 { set_advertising, MGMT_SETTING_SIZE },
6706 { set_bredr, MGMT_SETTING_SIZE },
6707 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6708 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6709 { set_secure_conn, MGMT_SETTING_SIZE },
6710 { set_debug_keys, MGMT_SETTING_SIZE },
6711 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006712 { load_irks, MGMT_LOAD_IRKS_SIZE,
6713 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006714 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6715 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6716 { add_device, MGMT_ADD_DEVICE_SIZE },
6717 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006718 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6719 HCI_MGMT_VAR_LEN },
6720 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006721 HCI_MGMT_NO_HDEV |
6722 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006723 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006724 HCI_MGMT_UNCONFIGURED |
6725 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006726 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6727 HCI_MGMT_UNCONFIGURED },
6728 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6729 HCI_MGMT_UNCONFIGURED },
6730 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6731 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006732 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006733 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006734 HCI_MGMT_NO_HDEV |
6735 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006736 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006737 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6738 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006739 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006740 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006741};
6742
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006743void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006744{
Marcel Holtmannced85542015-03-14 19:27:56 -07006745 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006746
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006747 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6748 return;
6749
Marcel Holtmannf9207332015-03-14 19:27:55 -07006750 switch (hdev->dev_type) {
6751 case HCI_BREDR:
6752 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6753 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6754 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006755 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006756 } else {
6757 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6758 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006759 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006760 }
6761 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006762 case HCI_AMP:
6763 ev.type = 0x02;
6764 break;
6765 default:
6766 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006767 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006768
6769 ev.bus = hdev->bus;
6770
6771 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6772 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006773}
6774
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006775void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006776{
Marcel Holtmannced85542015-03-14 19:27:56 -07006777 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006778 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006779
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006780 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6781 return;
6782
Marcel Holtmannf9207332015-03-14 19:27:55 -07006783 switch (hdev->dev_type) {
6784 case HCI_BREDR:
6785 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006786
Marcel Holtmannf9207332015-03-14 19:27:55 -07006787 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6788 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6789 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006790 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006791 } else {
6792 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6793 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006794 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006795 }
6796 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006797 case HCI_AMP:
6798 ev.type = 0x02;
6799 break;
6800 default:
6801 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006802 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006803
6804 ev.bus = hdev->bus;
6805
6806 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6807 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006808}
6809
Andre Guedes6046dc32014-02-26 20:21:51 -03006810/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006811static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006812{
6813 struct hci_conn_params *p;
6814
6815 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006816 /* Needed for AUTO_OFF case where might not "really"
6817 * have been powered off.
6818 */
6819 list_del_init(&p->action);
6820
6821 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006822 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006823 case HCI_AUTO_CONN_ALWAYS:
6824 list_add(&p->action, &hdev->pend_le_conns);
6825 break;
6826 case HCI_AUTO_CONN_REPORT:
6827 list_add(&p->action, &hdev->pend_le_reports);
6828 break;
6829 default:
6830 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006831 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006832 }
6833}
6834
Marcel Holtmann1904a852015-01-11 13:50:44 -08006835static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006836{
6837 struct cmd_lookup match = { NULL, hdev };
6838
6839 BT_DBG("status 0x%02x", status);
6840
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006841 if (!status) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006842 restart_le_actions(hdev);
6843 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006844 }
6845
Johan Hedberg229ab392013-03-15 17:06:53 -05006846 hci_dev_lock(hdev);
6847
6848 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6849
6850 new_settings(hdev, match.sk);
6851
6852 hci_dev_unlock(hdev);
6853
6854 if (match.sk)
6855 sock_put(match.sk);
6856}
6857
Johan Hedberg70da6242013-03-15 17:06:51 -05006858static int powered_update_hci(struct hci_dev *hdev)
6859{
Johan Hedberg890ea892013-03-15 17:06:52 -05006860 struct hci_request req;
Florian Grandel320b3bf2015-06-18 03:16:49 +02006861 struct adv_info *adv_instance;
Johan Hedberg70da6242013-03-15 17:06:51 -05006862 u8 link_sec;
6863
Johan Hedberg890ea892013-03-15 17:06:52 -05006864 hci_req_init(&req, hdev);
6865
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006866 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006867 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006868 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006869
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006870 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006871
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006872 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6873 u8 support = 0x01;
6874
6875 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6876 sizeof(support), &support);
6877 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006878 }
6879
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006880 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006881 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006882 struct hci_cp_write_le_host_supported cp;
6883
Marcel Holtmann32226e42014-07-24 20:04:16 +02006884 cp.le = 0x01;
6885 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006886
6887 /* Check first if we already have the right
6888 * host state (host features set)
6889 */
6890 if (cp.le != lmp_host_le_capable(hdev) ||
6891 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006892 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6893 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006894 }
6895
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006896 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006897 /* Make sure the controller has a good default for
6898 * advertising data. This also applies to the case
6899 * where BR/EDR was toggled during the AUTO_OFF phase.
6900 */
Florian Grandel320b3bf2015-06-18 03:16:49 +02006901 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
6902 (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6903 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
Johan Hedbergf2252572015-11-18 12:49:20 +02006904 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
6905 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006906 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006907
Florian Grandel320b3bf2015-06-18 03:16:49 +02006908 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6909 hdev->cur_adv_instance == 0x00 &&
6910 !list_empty(&hdev->adv_instances)) {
6911 adv_instance = list_first_entry(&hdev->adv_instances,
6912 struct adv_info, list);
6913 hdev->cur_adv_instance = adv_instance->instance;
6914 }
6915
6916 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergf2252572015-11-18 12:49:20 +02006917 __hci_req_enable_advertising(&req);
Florian Grandel320b3bf2015-06-18 03:16:49 +02006918 else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6919 hdev->cur_adv_instance)
Johan Hedbergf2252572015-11-18 12:49:20 +02006920 __hci_req_schedule_adv_instance(&req,
6921 hdev->cur_adv_instance,
6922 true);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006923 }
6924
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006925 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006926 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006927 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6928 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006929
6930 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006931 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006932 write_fast_connectable(&req, true);
6933 else
6934 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006935 __hci_req_update_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006936 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006937 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006938 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006939 }
6940
Johan Hedberg229ab392013-03-15 17:06:53 -05006941 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006942}
6943
Johan Hedberg744cf192011-11-08 20:40:14 +02006944int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006945{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006946 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006947 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006948 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006949
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006950 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006951 return 0;
6952
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006953 if (powered) {
Andrzej Kaczmareke59a5542015-11-22 21:42:21 +01006954 /* Register the available SMP channels (BR/EDR and LE) only
6955 * when successfully powering on the controller. This late
6956 * registration is required so that LE SMP can clearly
6957 * decide if the public address or static address is used.
6958 */
6959 smp_register(hdev);
6960
Johan Hedberg229ab392013-03-15 17:06:53 -05006961 if (powered_update_hci(hdev) == 0)
6962 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006963
Johan Hedberg229ab392013-03-15 17:06:53 -05006964 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6965 &match);
6966 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006967 }
6968
Johan Hedberg229ab392013-03-15 17:06:53 -05006969 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006970
6971 /* If the power off is because of hdev unregistration let
6972 * use the appropriate INVALID_INDEX status. Otherwise use
6973 * NOT_POWERED. We cover both scenarios here since later in
6974 * mgmt_index_removed() any hci_conn callbacks will have already
6975 * been triggered, potentially causing misleading DISCONNECTED
6976 * status responses.
6977 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006978 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006979 status = MGMT_STATUS_INVALID_INDEX;
6980 else
6981 status = MGMT_STATUS_NOT_POWERED;
6982
6983 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006984
6985 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006986 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6987 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006988
6989new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006990 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006991
6992 if (match.sk)
6993 sock_put(match.sk);
6994
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006995 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006996}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006997
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006998void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006999{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007000 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007001 u8 status;
7002
Johan Hedberg333ae952015-03-17 13:48:47 +02007003 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007004 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007005 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007006
7007 if (err == -ERFKILL)
7008 status = MGMT_STATUS_RFKILLED;
7009 else
7010 status = MGMT_STATUS_FAILED;
7011
Johan Hedberga69e8372015-03-06 21:08:53 +02007012 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007013
7014 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007015}
7016
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007017void mgmt_discoverable_timeout(struct hci_dev *hdev)
7018{
7019 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007020
7021 hci_dev_lock(hdev);
7022
7023 /* When discoverable timeout triggers, then just make sure
7024 * the limited discoverable flag is cleared. Even in the case
7025 * of a timeout triggered from general discoverable, it is
7026 * safe to unconditionally clear the flag.
7027 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007028 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
7029 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007030
7031 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007032 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03007033 u8 scan = SCAN_PAGE;
7034 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
7035 sizeof(scan), &scan);
7036 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007037 update_class(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07007038
7039 /* Advertising instances don't use the global discoverable setting, so
7040 * only update AD if advertising was enabled using Set Advertising.
7041 */
7042 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergf2252572015-11-18 12:49:20 +02007043 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Arman Uguray24b4f382015-03-23 15:57:12 -07007044
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007045 hci_req_run(&req, NULL);
7046
7047 hdev->discov_timeout = 0;
7048
Johan Hedberg9a43e252013-10-20 19:00:07 +03007049 new_settings(hdev, NULL);
7050
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007051 hci_dev_unlock(hdev);
7052}
7053
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007054void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7055 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007056{
Johan Hedberg86742e12011-11-07 23:13:38 +02007057 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007058
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007059 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007060
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007061 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007062 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007063 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007064 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007065 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007066 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007067
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007068 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007069}
Johan Hedbergf7520542011-01-20 12:34:39 +02007070
Johan Hedbergd7b25452014-05-23 13:19:53 +03007071static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7072{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007073 switch (ltk->type) {
7074 case SMP_LTK:
7075 case SMP_LTK_SLAVE:
7076 if (ltk->authenticated)
7077 return MGMT_LTK_AUTHENTICATED;
7078 return MGMT_LTK_UNAUTHENTICATED;
7079 case SMP_LTK_P256:
7080 if (ltk->authenticated)
7081 return MGMT_LTK_P256_AUTH;
7082 return MGMT_LTK_P256_UNAUTH;
7083 case SMP_LTK_P256_DEBUG:
7084 return MGMT_LTK_P256_DEBUG;
7085 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007086
7087 return MGMT_LTK_UNAUTHENTICATED;
7088}
7089
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007090void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007091{
7092 struct mgmt_ev_new_long_term_key ev;
7093
7094 memset(&ev, 0, sizeof(ev));
7095
Marcel Holtmann5192d302014-02-19 17:11:58 -08007096 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007097 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007098 * to store long term keys. Their addresses will change the
7099 * next time around.
7100 *
7101 * Only when a remote device provides an identity address
7102 * make sure the long term key is stored. If the remote
7103 * identity is known, the long term keys are internally
7104 * mapped to the identity address. So allow static random
7105 * and public addresses here.
7106 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007107 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7108 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7109 ev.store_hint = 0x00;
7110 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007111 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007112
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007113 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007114 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007115 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007116 ev.key.enc_size = key->enc_size;
7117 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007118 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007119
Johan Hedberg2ceba532014-06-16 19:25:16 +03007120 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007121 ev.key.master = 1;
7122
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007123 /* Make sure we copy only the significant bytes based on the
7124 * encryption key size, and set the rest of the value to zeroes.
7125 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007126 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007127 memset(ev.key.val + key->enc_size, 0,
7128 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007129
Marcel Holtmann083368f2013-10-15 14:26:29 -07007130 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007131}
7132
Johan Hedbergcad20c22015-10-12 13:36:19 +02007133void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007134{
7135 struct mgmt_ev_new_irk ev;
7136
7137 memset(&ev, 0, sizeof(ev));
7138
Johan Hedbergcad20c22015-10-12 13:36:19 +02007139 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007140
Johan Hedberg95fbac82014-02-19 15:18:31 +02007141 bacpy(&ev.rpa, &irk->rpa);
7142 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7143 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7144 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7145
7146 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7147}
7148
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007149void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7150 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007151{
7152 struct mgmt_ev_new_csrk ev;
7153
7154 memset(&ev, 0, sizeof(ev));
7155
7156 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007157 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007158 * to store signature resolving keys. Their addresses will change
7159 * the next time around.
7160 *
7161 * Only when a remote device provides an identity address
7162 * make sure the signature resolving key is stored. So allow
7163 * static random and public addresses here.
7164 */
7165 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7166 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7167 ev.store_hint = 0x00;
7168 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007169 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007170
7171 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7172 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007173 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007174 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7175
7176 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7177}
7178
Andre Guedesffb5a8272014-07-01 18:10:11 -03007179void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007180 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7181 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007182{
7183 struct mgmt_ev_new_conn_param ev;
7184
Johan Hedbergc103aea2014-07-02 17:37:34 +03007185 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7186 return;
7187
Andre Guedesffb5a8272014-07-01 18:10:11 -03007188 memset(&ev, 0, sizeof(ev));
7189 bacpy(&ev.addr.bdaddr, bdaddr);
7190 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007191 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007192 ev.min_interval = cpu_to_le16(min_interval);
7193 ev.max_interval = cpu_to_le16(max_interval);
7194 ev.latency = cpu_to_le16(latency);
7195 ev.timeout = cpu_to_le16(timeout);
7196
7197 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7198}
7199
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007200void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7201 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007202{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007203 char buf[512];
7204 struct mgmt_ev_device_connected *ev = (void *) buf;
7205 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007206
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007207 bacpy(&ev->addr.bdaddr, &conn->dst);
7208 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007209
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007210 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007211
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007212 /* We must ensure that the EIR Data fields are ordered and
7213 * unique. Keep it simple for now and avoid the problem by not
7214 * adding any BR/EDR data to the LE adv.
7215 */
7216 if (conn->le_adv_data_len > 0) {
7217 memcpy(&ev->eir[eir_len],
7218 conn->le_adv_data, conn->le_adv_data_len);
7219 eir_len = conn->le_adv_data_len;
7220 } else {
7221 if (name_len > 0)
7222 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7223 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007224
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007225 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007226 eir_len = eir_append_data(ev->eir, eir_len,
7227 EIR_CLASS_OF_DEV,
7228 conn->dev_class, 3);
7229 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007230
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007231 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007232
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007233 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7234 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007235}
7236
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007237static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007238{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007239 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007240
Johan Hedbergf5818c22014-12-05 13:36:02 +02007241 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007242
7243 *sk = cmd->sk;
7244 sock_hold(*sk);
7245
Johan Hedberga664b5b2011-02-19 12:06:02 -03007246 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007247}
7248
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007249static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007250{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007251 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007252 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007253
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007254 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7255
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007256 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007257 mgmt_pending_remove(cmd);
7258}
7259
Johan Hedberg84c61d92014-08-01 11:13:30 +03007260bool mgmt_powering_down(struct hci_dev *hdev)
7261{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007262 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007263 struct mgmt_mode *cp;
7264
Johan Hedberg333ae952015-03-17 13:48:47 +02007265 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007266 if (!cmd)
7267 return false;
7268
7269 cp = cmd->param;
7270 if (!cp->val)
7271 return true;
7272
7273 return false;
7274}
7275
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007276void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007277 u8 link_type, u8 addr_type, u8 reason,
7278 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007279{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007280 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007281 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007282
Johan Hedberg84c61d92014-08-01 11:13:30 +03007283 /* The connection is still in hci_conn_hash so test for 1
7284 * instead of 0 to know if this is the last one.
7285 */
7286 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7287 cancel_delayed_work(&hdev->power_off);
7288 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007289 }
7290
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007291 if (!mgmt_connected)
7292 return;
7293
Andre Guedes57eb7762013-10-30 19:01:41 -03007294 if (link_type != ACL_LINK && link_type != LE_LINK)
7295 return;
7296
Johan Hedberg744cf192011-11-08 20:40:14 +02007297 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007298
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007299 bacpy(&ev.addr.bdaddr, bdaddr);
7300 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7301 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007302
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007303 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007304
7305 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007306 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007307
Johan Hedberg124f6e32012-02-09 13:50:12 +02007308 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007309 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007310}
7311
Marcel Holtmann78929242013-10-06 23:55:47 -07007312void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7313 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007314{
Andre Guedes3655bba2013-10-30 19:01:40 -03007315 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7316 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007317 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007318
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007319 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7320 hdev);
7321
Johan Hedberg333ae952015-03-17 13:48:47 +02007322 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007323 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007324 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007325
Andre Guedes3655bba2013-10-30 19:01:40 -03007326 cp = cmd->param;
7327
7328 if (bacmp(bdaddr, &cp->addr.bdaddr))
7329 return;
7330
7331 if (cp->addr.type != bdaddr_type)
7332 return;
7333
Johan Hedbergf5818c22014-12-05 13:36:02 +02007334 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007335 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007336}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007337
Marcel Holtmann445608d2013-10-06 23:55:48 -07007338void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7339 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007340{
7341 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007342
Johan Hedberg84c61d92014-08-01 11:13:30 +03007343 /* The connection is still in hci_conn_hash so test for 1
7344 * instead of 0 to know if this is the last one.
7345 */
7346 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7347 cancel_delayed_work(&hdev->power_off);
7348 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007349 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007350
Johan Hedberg4c659c32011-11-07 23:13:39 +02007351 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007352 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007353 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007354
Marcel Holtmann445608d2013-10-06 23:55:48 -07007355 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007356}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007357
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007358void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007359{
7360 struct mgmt_ev_pin_code_request ev;
7361
Johan Hedbergd8457692012-02-17 14:24:57 +02007362 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007363 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007364 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007365
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007366 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007367}
7368
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007369void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7370 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007371{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007372 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007373
Johan Hedberg333ae952015-03-17 13:48:47 +02007374 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007375 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007376 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007377
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007378 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007379 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007380}
7381
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007382void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7383 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007384{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007385 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007386
Johan Hedberg333ae952015-03-17 13:48:47 +02007387 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007388 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007389 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007390
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007391 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007392 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007393}
Johan Hedberga5c29682011-02-19 12:05:57 -03007394
Johan Hedberg744cf192011-11-08 20:40:14 +02007395int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007396 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007397 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007398{
7399 struct mgmt_ev_user_confirm_request ev;
7400
Johan Hedberg744cf192011-11-08 20:40:14 +02007401 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007402
Johan Hedberg272d90d2012-02-09 15:26:12 +02007403 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007404 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007405 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007406 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007407
Johan Hedberg744cf192011-11-08 20:40:14 +02007408 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007409 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007410}
7411
Johan Hedberg272d90d2012-02-09 15:26:12 +02007412int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007413 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007414{
7415 struct mgmt_ev_user_passkey_request ev;
7416
7417 BT_DBG("%s", hdev->name);
7418
Johan Hedberg272d90d2012-02-09 15:26:12 +02007419 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007420 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007421
7422 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007423 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007424}
7425
Brian Gix0df4c182011-11-16 13:53:13 -08007426static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007427 u8 link_type, u8 addr_type, u8 status,
7428 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007429{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007430 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007431
Johan Hedberg333ae952015-03-17 13:48:47 +02007432 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007433 if (!cmd)
7434 return -ENOENT;
7435
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007436 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007437 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007438
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007439 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007440}
7441
Johan Hedberg744cf192011-11-08 20:40:14 +02007442int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007443 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007444{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007445 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007446 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007447}
7448
Johan Hedberg272d90d2012-02-09 15:26:12 +02007449int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007450 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007451{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007452 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007453 status,
7454 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007455}
Johan Hedberg2a611692011-02-19 12:06:00 -03007456
Brian Gix604086b2011-11-23 08:28:33 -08007457int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007458 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007459{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007460 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007461 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007462}
7463
Johan Hedberg272d90d2012-02-09 15:26:12 +02007464int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007465 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007466{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007467 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007468 status,
7469 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007470}
7471
Johan Hedberg92a25252012-09-06 18:39:26 +03007472int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7473 u8 link_type, u8 addr_type, u32 passkey,
7474 u8 entered)
7475{
7476 struct mgmt_ev_passkey_notify ev;
7477
7478 BT_DBG("%s", hdev->name);
7479
7480 bacpy(&ev.addr.bdaddr, bdaddr);
7481 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7482 ev.passkey = __cpu_to_le32(passkey);
7483 ev.entered = entered;
7484
7485 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7486}
7487
Johan Hedberge1e930f2014-09-08 17:09:49 -07007488void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007489{
7490 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007491 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007492 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007493
Johan Hedberge1e930f2014-09-08 17:09:49 -07007494 bacpy(&ev.addr.bdaddr, &conn->dst);
7495 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7496 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007497
Johan Hedberge1e930f2014-09-08 17:09:49 -07007498 cmd = find_pairing(conn);
7499
7500 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7501 cmd ? cmd->sk : NULL);
7502
Johan Hedberga511b352014-12-11 21:45:45 +02007503 if (cmd) {
7504 cmd->cmd_complete(cmd, status);
7505 mgmt_pending_remove(cmd);
7506 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007507}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007508
Marcel Holtmann464996a2013-10-15 14:26:24 -07007509void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007510{
7511 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007512 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007513
7514 if (status) {
7515 u8 mgmt_err = mgmt_status(status);
7516 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007517 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007518 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007519 }
7520
Marcel Holtmann464996a2013-10-15 14:26:24 -07007521 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007522 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007523 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007524 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007525
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007526 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007527 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007528
Johan Hedberg47990ea2012-02-22 11:58:37 +02007529 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007530 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007531
7532 if (match.sk)
7533 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007534}
7535
Johan Hedberg890ea892013-03-15 17:06:52 -05007536static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007537{
Johan Hedberg890ea892013-03-15 17:06:52 -05007538 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007539 struct hci_cp_write_eir cp;
7540
Johan Hedberg976eb202012-10-24 21:12:01 +03007541 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007542 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007543
Johan Hedbergc80da272012-02-22 15:38:48 +02007544 memset(hdev->eir, 0, sizeof(hdev->eir));
7545
Johan Hedbergcacaf522012-02-21 00:52:42 +02007546 memset(&cp, 0, sizeof(cp));
7547
Johan Hedberg890ea892013-03-15 17:06:52 -05007548 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007549}
7550
Marcel Holtmann3e248562013-10-15 14:26:25 -07007551void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007552{
7553 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007554 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007555 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007556
7557 if (status) {
7558 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007559
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007560 if (enable && hci_dev_test_and_clear_flag(hdev,
7561 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007562 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007563 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007564 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007565
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007566 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7567 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007568 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007569 }
7570
7571 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007572 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007573 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007574 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007575 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007576 changed = hci_dev_test_and_clear_flag(hdev,
7577 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007578 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007579 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007580 }
7581
7582 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7583
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007584 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007585 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007586
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007587 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007588 sock_put(match.sk);
7589
Johan Hedberg890ea892013-03-15 17:06:52 -05007590 hci_req_init(&req, hdev);
7591
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007592 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7593 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007594 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7595 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007596 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007597 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007598 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007599 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007600
7601 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007602}
7603
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007604static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007605{
7606 struct cmd_lookup *match = data;
7607
Johan Hedberg90e70452012-02-23 23:09:40 +02007608 if (match->sk == NULL) {
7609 match->sk = cmd->sk;
7610 sock_hold(match->sk);
7611 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007612}
7613
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007614void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7615 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007616{
Johan Hedberg90e70452012-02-23 23:09:40 +02007617 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007618
Johan Hedberg92da6092013-03-15 17:06:55 -05007619 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7620 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7621 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007622
7623 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007624 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7625 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007626
7627 if (match.sk)
7628 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007629}
7630
Marcel Holtmann7667da32013-10-15 14:26:27 -07007631void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007632{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007633 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007634 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007635
Johan Hedberg13928972013-03-15 17:07:00 -05007636 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007637 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007638
7639 memset(&ev, 0, sizeof(ev));
7640 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007641 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007642
Johan Hedberg333ae952015-03-17 13:48:47 +02007643 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007644 if (!cmd) {
7645 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007646
Johan Hedberg13928972013-03-15 17:07:00 -05007647 /* If this is a HCI command related to powering on the
7648 * HCI dev don't send any mgmt signals.
7649 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007650 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007651 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007652 }
7653
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007654 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7655 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007656}
Szymon Jancc35938b2011-03-22 13:12:21 +01007657
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007658static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7659{
7660 int i;
7661
7662 for (i = 0; i < uuid_count; i++) {
7663 if (!memcmp(uuid, uuids[i], 16))
7664 return true;
7665 }
7666
7667 return false;
7668}
7669
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007670static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7671{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007672 u16 parsed = 0;
7673
7674 while (parsed < eir_len) {
7675 u8 field_len = eir[0];
7676 u8 uuid[16];
7677 int i;
7678
7679 if (field_len == 0)
7680 break;
7681
7682 if (eir_len - parsed < field_len + 1)
7683 break;
7684
7685 switch (eir[1]) {
7686 case EIR_UUID16_ALL:
7687 case EIR_UUID16_SOME:
7688 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007689 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007690 uuid[13] = eir[i + 3];
7691 uuid[12] = eir[i + 2];
7692 if (has_uuid(uuid, uuid_count, uuids))
7693 return true;
7694 }
7695 break;
7696 case EIR_UUID32_ALL:
7697 case EIR_UUID32_SOME:
7698 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007699 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007700 uuid[15] = eir[i + 5];
7701 uuid[14] = eir[i + 4];
7702 uuid[13] = eir[i + 3];
7703 uuid[12] = eir[i + 2];
7704 if (has_uuid(uuid, uuid_count, uuids))
7705 return true;
7706 }
7707 break;
7708 case EIR_UUID128_ALL:
7709 case EIR_UUID128_SOME:
7710 for (i = 0; i + 17 <= field_len; i += 16) {
7711 memcpy(uuid, eir + i + 2, 16);
7712 if (has_uuid(uuid, uuid_count, uuids))
7713 return true;
7714 }
7715 break;
7716 }
7717
7718 parsed += field_len + 1;
7719 eir += field_len + 1;
7720 }
7721
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007722 return false;
7723}
7724
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007725static void restart_le_scan(struct hci_dev *hdev)
7726{
7727 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007728 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007729 return;
7730
7731 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7732 hdev->discovery.scan_start +
7733 hdev->discovery.scan_duration))
7734 return;
7735
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007736 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007737 DISCOV_LE_RESTART_DELAY);
7738}
7739
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007740static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7741 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7742{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007743 /* If a RSSI threshold has been specified, and
7744 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7745 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7746 * is set, let it through for further processing, as we might need to
7747 * restart the scan.
7748 *
7749 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7750 * the results are also dropped.
7751 */
7752 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7753 (rssi == HCI_RSSI_INVALID ||
7754 (rssi < hdev->discovery.rssi &&
7755 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7756 return false;
7757
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007758 if (hdev->discovery.uuid_count != 0) {
7759 /* If a list of UUIDs is provided in filter, results with no
7760 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007761 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007762 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7763 hdev->discovery.uuids) &&
7764 !eir_has_uuids(scan_rsp, scan_rsp_len,
7765 hdev->discovery.uuid_count,
7766 hdev->discovery.uuids))
7767 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007768 }
7769
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007770 /* If duplicate filtering does not report RSSI changes, then restart
7771 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007772 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007773 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7774 restart_le_scan(hdev);
7775
7776 /* Validate RSSI value against the RSSI threshold once more. */
7777 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7778 rssi < hdev->discovery.rssi)
7779 return false;
7780 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007781
7782 return true;
7783}
7784
Marcel Holtmann901801b2013-10-06 23:55:51 -07007785void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007786 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7787 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007788{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007789 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007790 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007791 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007792
Johan Hedberg75ce2082014-07-02 22:42:01 +03007793 /* Don't send events for a non-kernel initiated discovery. With
7794 * LE one exception is if we have pend_le_reports > 0 in which
7795 * case we're doing passive scanning and want these events.
7796 */
7797 if (!hci_discovery_active(hdev)) {
7798 if (link_type == ACL_LINK)
7799 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007800 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007801 return;
7802 }
Andre Guedes12602d02013-04-30 15:29:40 -03007803
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007804 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007805 /* We are using service discovery */
7806 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7807 scan_rsp_len))
7808 return;
7809 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007810
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007811 /* Make sure that the buffer is big enough. The 5 extra bytes
7812 * are for the potential CoD field.
7813 */
7814 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007815 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007816
Johan Hedberg1dc06092012-01-15 21:01:23 +02007817 memset(buf, 0, sizeof(buf));
7818
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007819 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7820 * RSSI value was reported as 0 when not available. This behavior
7821 * is kept when using device discovery. This is required for full
7822 * backwards compatibility with the API.
7823 *
7824 * However when using service discovery, the value 127 will be
7825 * returned when the RSSI is not available.
7826 */
Szymon Janc91200e92015-01-22 16:57:05 +01007827 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7828 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007829 rssi = 0;
7830
Johan Hedberg841c5642014-07-07 12:45:54 +03007831 bacpy(&ev->addr.bdaddr, bdaddr);
7832 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007833 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007834 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007835
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007836 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007837 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007838 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007839
Johan Hedberg1dc06092012-01-15 21:01:23 +02007840 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7841 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007842 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007843
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007844 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007845 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007846 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007847
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007848 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7849 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007850
Marcel Holtmann901801b2013-10-06 23:55:51 -07007851 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007852}
Johan Hedberga88a9652011-03-30 13:18:12 +03007853
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007854void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7855 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007856{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007857 struct mgmt_ev_device_found *ev;
7858 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7859 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007860
Johan Hedbergb644ba32012-01-17 21:48:47 +02007861 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007862
Johan Hedbergb644ba32012-01-17 21:48:47 +02007863 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007864
Johan Hedbergb644ba32012-01-17 21:48:47 +02007865 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007866 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007867 ev->rssi = rssi;
7868
7869 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007870 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007871
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007872 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007873
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007874 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007875}
Johan Hedberg314b2382011-04-27 10:29:57 -04007876
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007877void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007878{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007879 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007880
Andre Guedes343fb142011-11-22 17:14:19 -03007881 BT_DBG("%s discovering %u", hdev->name, discovering);
7882
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007883 memset(&ev, 0, sizeof(ev));
7884 ev.type = hdev->discovery.type;
7885 ev.discovering = discovering;
7886
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007887 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007888}
Antti Julku5e762442011-08-25 16:48:02 +03007889
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007890static struct hci_mgmt_chan chan = {
7891 .channel = HCI_CHANNEL_CONTROL,
7892 .handler_count = ARRAY_SIZE(mgmt_handlers),
7893 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007894 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007895};
7896
7897int mgmt_init(void)
7898{
7899 return hci_mgmt_chan_register(&chan);
7900}
7901
7902void mgmt_exit(void)
7903{
7904 hci_mgmt_chan_unregister(&chan);
7905}