blob: fa5dc67a800a0ad3f8fb384a55408096dbfdf380 [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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedberg333ae952015-03-17 13:48:47 +0200722static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
723{
724 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
725}
726
Johan Hedberg333ae952015-03-17 13:48:47 +0200727static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
728 struct hci_dev *hdev,
729 const void *data)
730{
731 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
732}
733
Johan Hedbergf2252572015-11-18 12:49:20 +0200734u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300735{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200736 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300737
738 /* If there's a pending mgmt command the flags will not yet have
739 * their final values, so check for this first.
740 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200741 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300742 if (cmd) {
743 struct mgmt_mode *cp = cmd->param;
744 if (cp->val == 0x01)
745 return LE_AD_GENERAL;
746 else if (cp->val == 0x02)
747 return LE_AD_LIMITED;
748 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700749 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300750 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700751 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300752 return LE_AD_GENERAL;
753 }
754
755 return 0;
756}
757
Johan Hedbergf2252572015-11-18 12:49:20 +0200758bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700759{
760 struct mgmt_pending_cmd *cmd;
761
762 /* If there's a pending mgmt command the flag will not yet have
763 * it's final value, so check for this first.
764 */
765 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
766 if (cmd) {
767 struct mgmt_mode *cp = cmd->param;
768
769 return cp->val;
770 }
771
772 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
773}
774
Johan Hedberg7d785252011-12-15 00:47:39 +0200775static void service_cache_off(struct work_struct *work)
776{
777 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300778 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500779 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200780
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700781 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200782 return;
783
Johan Hedberg890ea892013-03-15 17:06:52 -0500784 hci_req_init(&req, hdev);
785
Johan Hedberg7d785252011-12-15 00:47:39 +0200786 hci_dev_lock(hdev);
787
Johan Hedbergb1a89172015-11-25 16:15:42 +0200788 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200789 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200790
791 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500792
793 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200794}
795
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200796static void rpa_expired(struct work_struct *work)
797{
798 struct hci_dev *hdev = container_of(work, struct hci_dev,
799 rpa_expired.work);
800 struct hci_request req;
801
802 BT_DBG("");
803
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700804 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200805
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700806 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200807 return;
808
809 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200810 * controller happens in the hci_req_enable_advertising()
811 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200812 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200813 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +0200814 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200815 hci_req_run(&req, NULL);
816}
817
Johan Hedberg6a919082012-02-28 06:17:26 +0200818static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200819{
Marcel Holtmann238be782015-03-13 02:11:06 -0700820 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200821 return;
822
Johan Hedberg4f87da82012-03-02 19:55:56 +0200823 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200824 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200825
Johan Hedberg4f87da82012-03-02 19:55:56 +0200826 /* Non-mgmt controlled devices get this bit set
827 * implicitly so that pairing works for them, however
828 * for mgmt we require user-space to explicitly enable
829 * it
830 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700831 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200832}
833
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200834static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300835 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
837 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200838
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200839 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200840
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300841 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Johan Hedberg03811012010-12-08 00:21:06 +0200843 memset(&rp, 0, sizeof(rp));
844
Johan Hedberg03811012010-12-08 00:21:06 +0200845 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200846
847 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200848 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200849
850 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
851 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
852
853 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200854
855 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200856 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300858 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200859
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200860 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
861 sizeof(rp));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862}
863
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200864static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200865{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200866 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200867
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200868 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
869 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200870}
871
Marcel Holtmann1904a852015-01-11 13:50:44 -0800872static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200873{
874 BT_DBG("%s status 0x%02x", hdev->name, status);
875
Johan Hedberga3172b72014-02-28 09:33:44 +0200876 if (hci_conn_count(hdev) == 0) {
877 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200878 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200879 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200880}
881
Johan Hedbergf2252572015-11-18 12:49:20 +0200882void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700883{
884 struct mgmt_ev_advertising_added ev;
885
886 ev.instance = instance;
887
888 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
889}
890
Johan Hedbergf2252572015-11-18 12:49:20 +0200891void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
892 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700893{
894 struct mgmt_ev_advertising_removed ev;
895
896 ev.instance = instance;
897
898 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
899}
900
Florian Grandel7816b822015-06-18 03:16:45 +0200901static void cancel_adv_timeout(struct hci_dev *hdev)
902{
903 if (hdev->adv_instance_timeout) {
904 hdev->adv_instance_timeout = 0;
905 cancel_delayed_work(&hdev->adv_instance_expire);
906 }
907}
908
Johan Hedberg8b064a32014-02-24 14:52:22 +0200909static int clean_up_hci_state(struct hci_dev *hdev)
910{
911 struct hci_request req;
912 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300913 bool discov_stopped;
914 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200915
916 hci_req_init(&req, hdev);
917
918 if (test_bit(HCI_ISCAN, &hdev->flags) ||
919 test_bit(HCI_PSCAN, &hdev->flags)) {
920 u8 scan = 0x00;
921 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
922 }
923
Johan Hedbergf2252572015-11-18 12:49:20 +0200924 hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -0700925
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700926 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +0200927 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200928
Johan Hedberg2154d3f2015-11-11 08:30:45 +0200929 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200930
931 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +0300932 /* 0x15 == Terminated due to Power Off */
933 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200934 }
935
Johan Hedberg23a48092014-07-08 16:05:06 +0300936 err = hci_req_run(&req, clean_up_hci_complete);
937 if (!err && discov_stopped)
938 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
939
940 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200941}
942
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200943static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200945{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300946 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200947 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200948 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200950 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Johan Hedberga7e80f22013-01-09 16:05:19 +0200952 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +0200953 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
954 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +0200955
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300956 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200957
Johan Hedberg333ae952015-03-17 13:48:47 +0200958 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +0200959 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
960 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300961 goto failed;
962 }
963
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700964 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100965 cancel_delayed_work(&hdev->power_off);
966
967 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200968 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
969 data, len);
970 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100971 goto failed;
972 }
973 }
974
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200975 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200976 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200977 goto failed;
978 }
979
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200980 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
981 if (!cmd) {
982 err = -ENOMEM;
983 goto failed;
984 }
985
Johan Hedberg8b064a32014-02-24 14:52:22 +0200986 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +0200987 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200988 err = 0;
989 } else {
990 /* Disconnect connections, stop scans, etc */
991 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +0200992 if (!err)
993 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
994 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200995
Johan Hedberg8b064a32014-02-24 14:52:22 +0200996 /* ENODATA means there were no HCI commands queued */
997 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +0200998 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200999 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1000 err = 0;
1001 }
1002 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001003
1004failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001005 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 return err;
1007}
1008
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001009static int new_settings(struct hci_dev *hdev, struct sock *skip)
1010{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001011 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001012
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001013 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1014 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001015}
1016
Johan Hedberg91a668b2014-07-09 13:28:26 +03001017int mgmt_new_settings(struct hci_dev *hdev)
1018{
1019 return new_settings(hdev, NULL);
1020}
1021
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001022struct cmd_lookup {
1023 struct sock *sk;
1024 struct hci_dev *hdev;
1025 u8 mgmt_status;
1026};
1027
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001028static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001029{
1030 struct cmd_lookup *match = data;
1031
1032 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1033
1034 list_del(&cmd->list);
1035
1036 if (match->sk == NULL) {
1037 match->sk = cmd->sk;
1038 sock_hold(match->sk);
1039 }
1040
1041 mgmt_pending_free(cmd);
1042}
1043
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001044static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001045{
1046 u8 *status = data;
1047
Johan Hedberga69e8372015-03-06 21:08:53 +02001048 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001049 mgmt_pending_remove(cmd);
1050}
1051
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001052static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001053{
1054 if (cmd->cmd_complete) {
1055 u8 *status = data;
1056
1057 cmd->cmd_complete(cmd, *status);
1058 mgmt_pending_remove(cmd);
1059
1060 return;
1061 }
1062
1063 cmd_status_rsp(cmd, data);
1064}
1065
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001066static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001067{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001068 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1069 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001070}
1071
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001072static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001073{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001074 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1075 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001076}
1077
Johan Hedberge6fe7982013-10-02 15:45:22 +03001078static u8 mgmt_bredr_support(struct hci_dev *hdev)
1079{
1080 if (!lmp_bredr_capable(hdev))
1081 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001082 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001083 return MGMT_STATUS_REJECTED;
1084 else
1085 return MGMT_STATUS_SUCCESS;
1086}
1087
1088static u8 mgmt_le_support(struct hci_dev *hdev)
1089{
1090 if (!lmp_le_capable(hdev))
1091 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001092 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001093 return MGMT_STATUS_REJECTED;
1094 else
1095 return MGMT_STATUS_SUCCESS;
1096}
1097
Johan Hedbergaed1a882015-11-22 17:24:44 +03001098void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001099{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001100 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001101
1102 BT_DBG("status 0x%02x", status);
1103
1104 hci_dev_lock(hdev);
1105
Johan Hedberg333ae952015-03-17 13:48:47 +02001106 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001107 if (!cmd)
1108 goto unlock;
1109
1110 if (status) {
1111 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001112 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001113 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001114 goto remove_cmd;
1115 }
1116
Johan Hedbergaed1a882015-11-22 17:24:44 +03001117 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1118 hdev->discov_timeout > 0) {
1119 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1120 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001121 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001122
1123 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001124 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001125
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001126remove_cmd:
1127 mgmt_pending_remove(cmd);
1128
1129unlock:
1130 hci_dev_unlock(hdev);
1131}
1132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001133static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001134 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001135{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001136 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001137 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001138 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001139 int err;
1140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001141 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001142
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001143 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1144 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001145 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1146 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001147
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001148 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001149 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1150 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001151
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001152 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001153
1154 /* Disabling discoverable requires that no timeout is set,
1155 * and enabling limited discoverable requires a timeout.
1156 */
1157 if ((cp->val == 0x00 && timeout > 0) ||
1158 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001159 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1160 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001162 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001163
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001164 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001165 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1166 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001167 goto failed;
1168 }
1169
Johan Hedberg333ae952015-03-17 13:48:47 +02001170 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1171 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001172 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1173 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001174 goto failed;
1175 }
1176
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001177 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001178 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1179 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001180 goto failed;
1181 }
1182
1183 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001184 bool changed = false;
1185
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001186 /* Setting limited discoverable when powered off is
1187 * not a valid operation since it requires a timeout
1188 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1189 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001190 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001191 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001192 changed = true;
1193 }
1194
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001195 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001196 if (err < 0)
1197 goto failed;
1198
1199 if (changed)
1200 err = new_settings(hdev, sk);
1201
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001202 goto failed;
1203 }
1204
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001205 /* If the current mode is the same, then just update the timeout
1206 * value with the new value. And if only the timeout gets updated,
1207 * then no need for any HCI transactions.
1208 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001209 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1210 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1211 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001212 cancel_delayed_work(&hdev->discov_off);
1213 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001214
Marcel Holtmann36261542013-10-15 08:28:51 -07001215 if (cp->val && hdev->discov_timeout > 0) {
1216 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001217 queue_delayed_work(hdev->req_workqueue,
1218 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001219 }
1220
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001221 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001222 goto failed;
1223 }
1224
1225 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1226 if (!cmd) {
1227 err = -ENOMEM;
1228 goto failed;
1229 }
1230
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001231 /* Cancel any potential discoverable timeout that might be
1232 * still active and store new timeout value. The arming of
1233 * the timeout happens in the complete handler.
1234 */
1235 cancel_delayed_work(&hdev->discov_off);
1236 hdev->discov_timeout = timeout;
1237
Johan Hedbergaed1a882015-11-22 17:24:44 +03001238 if (cp->val)
1239 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1240 else
1241 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1242
Johan Hedbergb456f872013-10-19 23:38:22 +03001243 /* Limited discoverable mode */
1244 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001245 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001246 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001247 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001248
Johan Hedbergaed1a882015-11-22 17:24:44 +03001249 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1250 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001251
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001252failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001253 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001254 return err;
1255}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001256
Johan Hedberg406d7802013-03-15 17:07:09 -05001257static void write_fast_connectable(struct hci_request *req, bool enable)
1258{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001259 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001260 struct hci_cp_write_page_scan_activity acp;
1261 u8 type;
1262
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001263 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001264 return;
1265
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001266 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1267 return;
1268
Johan Hedberg406d7802013-03-15 17:07:09 -05001269 if (enable) {
1270 type = PAGE_SCAN_TYPE_INTERLACED;
1271
1272 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001273 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001274 } else {
1275 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1276
1277 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001278 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001279 }
1280
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001281 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001282
Johan Hedbergbd98b992013-03-15 17:07:13 -05001283 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1284 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1285 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1286 sizeof(acp), &acp);
1287
1288 if (hdev->page_scan_type != type)
1289 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001290}
1291
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001292void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001293{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001294 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001295
1296 BT_DBG("status 0x%02x", status);
1297
1298 hci_dev_lock(hdev);
1299
Johan Hedberg333ae952015-03-17 13:48:47 +02001300 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001301 if (!cmd)
1302 goto unlock;
1303
Johan Hedberg37438c12013-10-14 16:20:05 +03001304 if (status) {
1305 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001306 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001307 goto remove_cmd;
1308 }
1309
Johan Hedberg2b76f452013-03-15 17:07:04 -05001310 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001311 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001312
Johan Hedberg37438c12013-10-14 16:20:05 +03001313remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001314 mgmt_pending_remove(cmd);
1315
1316unlock:
1317 hci_dev_unlock(hdev);
1318}
1319
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001320static int set_connectable_update_settings(struct hci_dev *hdev,
1321 struct sock *sk, u8 val)
1322{
1323 bool changed = false;
1324 int err;
1325
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001326 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001327 changed = true;
1328
1329 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001330 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001331 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001332 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1333 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001334 }
1335
1336 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1337 if (err < 0)
1338 return err;
1339
Johan Hedberg562064e2014-07-08 16:35:34 +03001340 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001341 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001342 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001343 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001344 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001345
1346 return 0;
1347}
1348
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001349static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001350 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001351{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001352 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001353 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001354 int err;
1355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001356 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001357
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001358 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1359 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001360 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1361 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001362
Johan Hedberga7e80f22013-01-09 16:05:19 +02001363 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001364 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1365 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001366
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001367 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001368
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001369 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001370 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001371 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001372 }
1373
Johan Hedberg333ae952015-03-17 13:48:47 +02001374 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1375 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001376 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1377 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001378 goto failed;
1379 }
1380
Johan Hedberg73f22f62010-12-29 16:00:25 +02001381 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1382 if (!cmd) {
1383 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001384 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001385 }
1386
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001387 if (cp->val) {
1388 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1389 } else {
1390 if (hdev->discov_timeout > 0)
1391 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001392
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001393 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1394 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1395 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001396 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001397
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001398 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1399 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001400
1401failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001402 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001403 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001404}
1405
Johan Hedbergb2939472014-07-30 09:22:23 +03001406static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001407 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001408{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001409 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001410 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001411 int err;
1412
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001413 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001414
Johan Hedberga7e80f22013-01-09 16:05:19 +02001415 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001416 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1417 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001418
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001419 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001420
1421 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001422 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001423 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001424 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001425
Johan Hedbergb2939472014-07-30 09:22:23 +03001426 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001427 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001428 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001429
Marcel Holtmann55594352013-10-06 16:11:57 -07001430 if (changed)
1431 err = new_settings(hdev, sk);
Johan Hedberg053f0212011-01-26 13:07:10 +02001432
Marcel Holtmann55594352013-10-06 16:11:57 -07001433unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001434 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001435 return err;
1436}
1437
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001438static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1439 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001440{
1441 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001442 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001443 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001444 int err;
1445
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001446 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001447
Johan Hedberge6fe7982013-10-02 15:45:22 +03001448 status = mgmt_bredr_support(hdev);
1449 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001450 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1451 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001452
Johan Hedberga7e80f22013-01-09 16:05:19 +02001453 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001454 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1455 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001456
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001457 hci_dev_lock(hdev);
1458
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001459 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001460 bool changed = false;
1461
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001462 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001463 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001464 changed = true;
1465 }
1466
1467 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1468 if (err < 0)
1469 goto failed;
1470
1471 if (changed)
1472 err = new_settings(hdev, sk);
1473
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001474 goto failed;
1475 }
1476
Johan Hedberg333ae952015-03-17 13:48:47 +02001477 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001478 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1479 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001480 goto failed;
1481 }
1482
1483 val = !!cp->val;
1484
1485 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1486 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1487 goto failed;
1488 }
1489
1490 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1491 if (!cmd) {
1492 err = -ENOMEM;
1493 goto failed;
1494 }
1495
1496 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1497 if (err < 0) {
1498 mgmt_pending_remove(cmd);
1499 goto failed;
1500 }
1501
1502failed:
1503 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001504 return err;
1505}
1506
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001507static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001508{
1509 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001510 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001511 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001512 int err;
1513
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001514 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001515
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001516 status = mgmt_bredr_support(hdev);
1517 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001518 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001519
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001520 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001521 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1522 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001523
Johan Hedberga7e80f22013-01-09 16:05:19 +02001524 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001525 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1526 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001527
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001528 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001529
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001530 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001531 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001532
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001533 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001534 changed = !hci_dev_test_and_set_flag(hdev,
1535 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001536 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001537 changed = hci_dev_test_and_clear_flag(hdev,
1538 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001539 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001540 changed = hci_dev_test_and_clear_flag(hdev,
1541 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001542 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001543 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001544 }
1545
1546 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1547 if (err < 0)
1548 goto failed;
1549
1550 if (changed)
1551 err = new_settings(hdev, sk);
1552
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001553 goto failed;
1554 }
1555
Johan Hedberg333ae952015-03-17 13:48:47 +02001556 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001557 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1558 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001559 goto failed;
1560 }
1561
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001562 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001563 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1564 goto failed;
1565 }
1566
1567 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1568 if (!cmd) {
1569 err = -ENOMEM;
1570 goto failed;
1571 }
1572
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001573 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001574 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1575 sizeof(cp->val), &cp->val);
1576
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001577 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001578 if (err < 0) {
1579 mgmt_pending_remove(cmd);
1580 goto failed;
1581 }
1582
1583failed:
1584 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001585 return err;
1586}
1587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001588static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001589{
1590 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001591 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001592 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001593 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001595 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001596
Johan Hedberge6fe7982013-10-02 15:45:22 +03001597 status = mgmt_bredr_support(hdev);
1598 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001599 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001600
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001601 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001602 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1603 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001604
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001605 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001606 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1607 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001608
Johan Hedberga7e80f22013-01-09 16:05:19 +02001609 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001610 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1611 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001612
Marcel Holtmannee392692013-10-01 22:59:23 -07001613 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001614
Johan Hedberg333ae952015-03-17 13:48:47 +02001615 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001616 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1617 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001618 goto unlock;
1619 }
1620
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001621 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001622 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001623 } else {
1624 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001625 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1626 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001627 goto unlock;
1628 }
1629
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001630 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001631 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001632
1633 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1634 if (err < 0)
1635 goto unlock;
1636
1637 if (changed)
1638 err = new_settings(hdev, sk);
1639
1640unlock:
1641 hci_dev_unlock(hdev);
1642 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001643}
1644
Marcel Holtmann1904a852015-01-11 13:50:44 -08001645static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001646{
1647 struct cmd_lookup match = { NULL, hdev };
1648
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301649 hci_dev_lock(hdev);
1650
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001651 if (status) {
1652 u8 mgmt_err = mgmt_status(status);
1653
1654 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1655 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301656 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001657 }
1658
1659 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1660
1661 new_settings(hdev, match.sk);
1662
1663 if (match.sk)
1664 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001665
1666 /* Make sure the controller has a good default for
1667 * advertising data. Restrict the update to when LE
1668 * has actually been enabled. During power on, the
1669 * update in powered_update_hci will take care of it.
1670 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001671 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001672 struct hci_request req;
1673
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001674 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001675 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
1676 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001677 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001678 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001679 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301680
1681unlock:
1682 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001683}
1684
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001685static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001686{
1687 struct mgmt_mode *cp = data;
1688 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001689 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001690 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001691 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001692 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001693
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001694 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001695
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001696 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001697 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1698 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001699
Johan Hedberga7e80f22013-01-09 16:05:19 +02001700 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001701 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1702 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001703
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001704 /* Bluetooth single mode LE only controllers or dual-mode
1705 * controllers configured as LE only devices, do not allow
1706 * switching LE off. These have either LE enabled explicitly
1707 * or BR/EDR has been previously switched off.
1708 *
1709 * When trying to enable an already enabled LE, then gracefully
1710 * send a positive response. Trying to disable it however will
1711 * result into rejection.
1712 */
1713 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1714 if (cp->val == 0x01)
1715 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1716
Johan Hedberga69e8372015-03-06 21:08:53 +02001717 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1718 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001719 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001720
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001721 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001722
1723 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001724 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001725
Florian Grandel847818d2015-06-18 03:16:46 +02001726 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02001727 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001728
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001729 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001730 bool changed = false;
1731
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001732 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001733 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001734 changed = true;
1735 }
1736
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001737 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001738 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001739 changed = true;
1740 }
1741
Johan Hedberg06199cf2012-02-22 16:37:11 +02001742 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1743 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001744 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001745
1746 if (changed)
1747 err = new_settings(hdev, sk);
1748
Johan Hedberg1de028c2012-02-29 19:55:35 -08001749 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001750 }
1751
Johan Hedberg333ae952015-03-17 13:48:47 +02001752 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1753 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001754 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1755 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001756 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001757 }
1758
1759 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1760 if (!cmd) {
1761 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001762 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001763 }
1764
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001765 hci_req_init(&req, hdev);
1766
Johan Hedberg06199cf2012-02-22 16:37:11 +02001767 memset(&hci_cp, 0, sizeof(hci_cp));
1768
1769 if (val) {
1770 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001771 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001772 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001773 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001774 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001775 }
1776
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001777 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1778 &hci_cp);
1779
1780 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301781 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001782 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001783
Johan Hedberg1de028c2012-02-29 19:55:35 -08001784unlock:
1785 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001786 return err;
1787}
1788
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001789/* This is a helper function to test for pending mgmt commands that can
1790 * cause CoD or EIR HCI commands. We can only allow one such pending
1791 * mgmt command at a time since otherwise we cannot easily track what
1792 * the current values are, will be, and based on that calculate if a new
1793 * HCI command needs to be sent and if yes with what value.
1794 */
1795static bool pending_eir_or_class(struct hci_dev *hdev)
1796{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001797 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001798
1799 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1800 switch (cmd->opcode) {
1801 case MGMT_OP_ADD_UUID:
1802 case MGMT_OP_REMOVE_UUID:
1803 case MGMT_OP_SET_DEV_CLASS:
1804 case MGMT_OP_SET_POWERED:
1805 return true;
1806 }
1807 }
1808
1809 return false;
1810}
1811
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001812static const u8 bluetooth_base_uuid[] = {
1813 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1814 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1815};
1816
1817static u8 get_uuid_size(const u8 *uuid)
1818{
1819 u32 val;
1820
1821 if (memcmp(uuid, bluetooth_base_uuid, 12))
1822 return 128;
1823
1824 val = get_unaligned_le32(&uuid[12]);
1825 if (val > 0xffff)
1826 return 32;
1827
1828 return 16;
1829}
1830
Johan Hedberg92da6092013-03-15 17:06:55 -05001831static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1832{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001833 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001834
1835 hci_dev_lock(hdev);
1836
Johan Hedberg333ae952015-03-17 13:48:47 +02001837 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001838 if (!cmd)
1839 goto unlock;
1840
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001841 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1842 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001843
1844 mgmt_pending_remove(cmd);
1845
1846unlock:
1847 hci_dev_unlock(hdev);
1848}
1849
Marcel Holtmann1904a852015-01-11 13:50:44 -08001850static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001851{
1852 BT_DBG("status 0x%02x", status);
1853
1854 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1855}
1856
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001857static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001858{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001859 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001860 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001861 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001862 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001863 int err;
1864
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001865 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001866
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001867 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001868
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001869 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001870 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1871 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001872 goto failed;
1873 }
1874
Andre Guedes92c4c202012-06-07 19:05:44 -03001875 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001876 if (!uuid) {
1877 err = -ENOMEM;
1878 goto failed;
1879 }
1880
1881 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001882 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001883 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001884
Johan Hedbergde66aa62013-01-27 00:31:27 +02001885 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001886
Johan Hedberg890ea892013-03-15 17:06:52 -05001887 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001888
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001889 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001890 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001891
Johan Hedberg92da6092013-03-15 17:06:55 -05001892 err = hci_req_run(&req, add_uuid_complete);
1893 if (err < 0) {
1894 if (err != -ENODATA)
1895 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001896
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001897 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1898 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001899 goto failed;
1900 }
1901
1902 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001903 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001904 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001905 goto failed;
1906 }
1907
1908 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001909
1910failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001911 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001912 return err;
1913}
1914
Johan Hedberg24b78d02012-02-23 23:24:30 +02001915static bool enable_service_cache(struct hci_dev *hdev)
1916{
1917 if (!hdev_is_powered(hdev))
1918 return false;
1919
Marcel Holtmann238be782015-03-13 02:11:06 -07001920 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001921 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1922 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001923 return true;
1924 }
1925
1926 return false;
1927}
1928
Marcel Holtmann1904a852015-01-11 13:50:44 -08001929static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001930{
1931 BT_DBG("status 0x%02x", status);
1932
1933 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1934}
1935
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001936static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001937 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001938{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001939 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001940 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001941 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001942 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 -05001943 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001944 int err, found;
1945
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001946 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001947
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001948 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001949
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001950 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001951 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1952 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001953 goto unlock;
1954 }
1955
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001956 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02001957 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001958
Johan Hedberg24b78d02012-02-23 23:24:30 +02001959 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001960 err = mgmt_cmd_complete(sk, hdev->id,
1961 MGMT_OP_REMOVE_UUID,
1962 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001963 goto unlock;
1964 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001965
Johan Hedberg9246a862012-02-23 21:33:16 +02001966 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001967 }
1968
1969 found = 0;
1970
Johan Hedberg056341c2013-01-27 00:31:30 +02001971 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001972 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1973 continue;
1974
1975 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001976 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001977 found++;
1978 }
1979
1980 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001981 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1982 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001983 goto unlock;
1984 }
1985
Johan Hedberg9246a862012-02-23 21:33:16 +02001986update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001987 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001988
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001989 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001990 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001991
Johan Hedberg92da6092013-03-15 17:06:55 -05001992 err = hci_req_run(&req, remove_uuid_complete);
1993 if (err < 0) {
1994 if (err != -ENODATA)
1995 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001996
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001997 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
1998 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001999 goto unlock;
2000 }
2001
2002 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002003 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002004 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002005 goto unlock;
2006 }
2007
2008 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002009
2010unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002011 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002012 return err;
2013}
2014
Marcel Holtmann1904a852015-01-11 13:50:44 -08002015static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002016{
2017 BT_DBG("status 0x%02x", status);
2018
2019 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2020}
2021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002022static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002023 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002024{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002025 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002026 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002027 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002028 int err;
2029
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002030 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002031
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002032 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002033 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2034 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002035
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002036 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002037
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002038 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002039 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2040 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002041 goto unlock;
2042 }
2043
2044 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002045 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002047 goto unlock;
2048 }
2049
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002050 hdev->major_class = cp->major;
2051 hdev->minor_class = cp->minor;
2052
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002053 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002054 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2055 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002056 goto unlock;
2057 }
2058
Johan Hedberg890ea892013-03-15 17:06:52 -05002059 hci_req_init(&req, hdev);
2060
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002061 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002062 hci_dev_unlock(hdev);
2063 cancel_delayed_work_sync(&hdev->service_cache);
2064 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002065 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002066 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002067
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002068 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002069
Johan Hedberg92da6092013-03-15 17:06:55 -05002070 err = hci_req_run(&req, set_class_complete);
2071 if (err < 0) {
2072 if (err != -ENODATA)
2073 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002074
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002075 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2076 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002077 goto unlock;
2078 }
2079
2080 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002081 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002082 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002083 goto unlock;
2084 }
2085
2086 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002087
Johan Hedbergb5235a62012-02-21 14:32:24 +02002088unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002090 return err;
2091}
2092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002093static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002094 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002095{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002096 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002097 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2098 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002099 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002100 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002101 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002102
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002103 BT_DBG("request for %s", hdev->name);
2104
2105 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002106 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2107 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002108
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002109 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002110 if (key_count > max_key_count) {
2111 BT_ERR("load_link_keys: too big key_count value %u",
2112 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002113 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2114 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002115 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002116
Johan Hedberg86742e12011-11-07 23:13:38 +02002117 expected_len = sizeof(*cp) + key_count *
2118 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002119 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002120 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002121 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002122 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2123 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002124 }
2125
Johan Hedberg4ae14302013-01-20 14:27:13 +02002126 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002127 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2128 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002129
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002130 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002131 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002132
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002133 for (i = 0; i < key_count; i++) {
2134 struct mgmt_link_key_info *key = &cp->keys[i];
2135
Marcel Holtmann8e991132014-01-10 02:07:25 -08002136 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002137 return mgmt_cmd_status(sk, hdev->id,
2138 MGMT_OP_LOAD_LINK_KEYS,
2139 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002140 }
2141
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002142 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002143
2144 hci_link_keys_clear(hdev);
2145
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002146 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002147 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002148 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002149 changed = hci_dev_test_and_clear_flag(hdev,
2150 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002151
2152 if (changed)
2153 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002154
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002155 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002156 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002157
Johan Hedberg58e92932014-06-24 14:00:26 +03002158 /* Always ignore debug keys and require a new pairing if
2159 * the user wants to use them.
2160 */
2161 if (key->type == HCI_LK_DEBUG_COMBINATION)
2162 continue;
2163
Johan Hedberg7652ff62014-06-24 13:15:49 +03002164 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2165 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002166 }
2167
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002168 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002170 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002171
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002172 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002173}
2174
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002175static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002177{
2178 struct mgmt_ev_device_unpaired ev;
2179
2180 bacpy(&ev.addr.bdaddr, bdaddr);
2181 ev.addr.type = addr_type;
2182
2183 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002184 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002185}
2186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002188 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002189{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002190 struct mgmt_cp_unpair_device *cp = data;
2191 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002192 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002193 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002194 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002195 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002196 int err;
2197
Johan Hedberga8a1d192011-11-10 15:54:38 +02002198 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002199 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2200 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002201
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002202 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002203 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2204 MGMT_STATUS_INVALID_PARAMS,
2205 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002206
Johan Hedberg118da702013-01-20 14:27:20 +02002207 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002208 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2209 MGMT_STATUS_INVALID_PARAMS,
2210 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002211
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002212 hci_dev_lock(hdev);
2213
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002214 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002215 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2216 MGMT_STATUS_NOT_POWERED, &rp,
2217 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002218 goto unlock;
2219 }
2220
Johan Hedberge0b2b272014-02-18 17:14:31 +02002221 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002222 /* If disconnection is requested, then look up the
2223 * connection. If the remote device is connected, it
2224 * will be later used to terminate the link.
2225 *
2226 * Setting it to NULL explicitly will cause no
2227 * termination of the link.
2228 */
2229 if (cp->disconnect)
2230 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2231 &cp->addr.bdaddr);
2232 else
2233 conn = NULL;
2234
Johan Hedberg124f6e32012-02-09 13:50:12 +02002235 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002236 if (err < 0) {
2237 err = mgmt_cmd_complete(sk, hdev->id,
2238 MGMT_OP_UNPAIR_DEVICE,
2239 MGMT_STATUS_NOT_PAIRED, &rp,
2240 sizeof(rp));
2241 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002242 }
2243
Johan Hedbergec182f02015-10-21 18:03:03 +03002244 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002245 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002246
Johan Hedbergec182f02015-10-21 18:03:03 +03002247 /* LE address type */
2248 addr_type = le_addr_type(cp->addr.type);
2249
2250 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2251
2252 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002254 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2255 MGMT_STATUS_NOT_PAIRED, &rp,
2256 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002257 goto unlock;
2258 }
2259
Johan Hedbergec182f02015-10-21 18:03:03 +03002260 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2261 if (!conn) {
2262 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2263 goto done;
2264 }
2265
Johan Hedbergc81d5552015-10-22 09:38:35 +03002266 /* Abort any ongoing SMP pairing */
2267 smp_cancel_pairing(conn);
2268
Johan Hedbergec182f02015-10-21 18:03:03 +03002269 /* Defer clearing up the connection parameters until closing to
2270 * give a chance of keeping them if a repairing happens.
2271 */
2272 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2273
Johan Hedbergfc643612015-10-22 09:38:31 +03002274 /* Disable auto-connection parameters if present */
2275 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2276 if (params) {
2277 if (params->explicit_connect)
2278 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2279 else
2280 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2281 }
2282
Johan Hedbergec182f02015-10-21 18:03:03 +03002283 /* If disconnection is not requested, then clear the connection
2284 * variable so that the link is not terminated.
2285 */
2286 if (!cp->disconnect)
2287 conn = NULL;
2288
2289done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002290 /* If the connection variable is set, then termination of the
2291 * link is requested.
2292 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002293 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002294 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2295 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002296 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002297 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002298 }
2299
Johan Hedberg124f6e32012-02-09 13:50:12 +02002300 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002301 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002302 if (!cmd) {
2303 err = -ENOMEM;
2304 goto unlock;
2305 }
2306
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002307 cmd->cmd_complete = addr_cmd_complete;
2308
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002309 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002310 if (err < 0)
2311 mgmt_pending_remove(cmd);
2312
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002313unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002314 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002315 return err;
2316}
2317
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002318static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002319 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002320{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002321 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002322 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002323 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002324 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002325 int err;
2326
2327 BT_DBG("");
2328
Johan Hedberg06a63b12013-01-20 14:27:21 +02002329 memset(&rp, 0, sizeof(rp));
2330 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2331 rp.addr.type = cp->addr.type;
2332
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002333 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002334 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2335 MGMT_STATUS_INVALID_PARAMS,
2336 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002337
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002338 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002339
2340 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002341 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2342 MGMT_STATUS_NOT_POWERED, &rp,
2343 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002344 goto failed;
2345 }
2346
Johan Hedberg333ae952015-03-17 13:48:47 +02002347 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002348 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2349 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002350 goto failed;
2351 }
2352
Andre Guedes591f47f2012-04-24 21:02:49 -03002353 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002354 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2355 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002356 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002357 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2358 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002359
Vishal Agarwalf9607272012-06-13 05:32:43 +05302360 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002361 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2362 MGMT_STATUS_NOT_CONNECTED, &rp,
2363 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364 goto failed;
2365 }
2366
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002367 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002368 if (!cmd) {
2369 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002370 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002371 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372
Johan Hedbergf5818c22014-12-05 13:36:02 +02002373 cmd->cmd_complete = generic_cmd_complete;
2374
Johan Hedberge3f2f922014-08-18 20:33:33 +03002375 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002376 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002377 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002378
2379failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002381 return err;
2382}
2383
Andre Guedes57c14772012-04-24 21:02:50 -03002384static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002385{
2386 switch (link_type) {
2387 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002388 switch (addr_type) {
2389 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002390 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002391
Johan Hedberg48264f02011-11-09 13:58:58 +02002392 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002393 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002394 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002395 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002396
Johan Hedberg4c659c32011-11-07 23:13:39 +02002397 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002398 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002399 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002400 }
2401}
2402
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002403static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2404 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002405{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002406 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002407 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002408 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002409 int err;
2410 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002411
2412 BT_DBG("");
2413
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002414 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002415
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002416 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002417 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2418 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002419 goto unlock;
2420 }
2421
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002422 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002423 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2424 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002425 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002426 }
2427
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002428 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002429 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002430 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002431 err = -ENOMEM;
2432 goto unlock;
2433 }
2434
Johan Hedberg2784eb42011-01-21 13:56:35 +02002435 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002436 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002437 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2438 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002439 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002440 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002441 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002442 continue;
2443 i++;
2444 }
2445
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002446 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002447
Johan Hedberg4c659c32011-11-07 23:13:39 +02002448 /* Recalculate length in case of filtered SCO connections, etc */
2449 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002450
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002451 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2452 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002453
Johan Hedberga38528f2011-01-22 06:46:43 +02002454 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002455
2456unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002457 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002458 return err;
2459}
2460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002463{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002464 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002465 int err;
2466
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002467 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002469 if (!cmd)
2470 return -ENOMEM;
2471
Johan Hedbergd8457692012-02-17 14:24:57 +02002472 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002474 if (err < 0)
2475 mgmt_pending_remove(cmd);
2476
2477 return err;
2478}
2479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002480static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002481 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002482{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002483 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002484 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002486 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002487 int err;
2488
2489 BT_DBG("");
2490
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002491 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002492
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002493 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002494 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2495 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002496 goto failed;
2497 }
2498
Johan Hedbergd8457692012-02-17 14:24:57 +02002499 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002500 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002501 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2502 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002503 goto failed;
2504 }
2505
2506 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002507 struct mgmt_cp_pin_code_neg_reply ncp;
2508
2509 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002510
2511 BT_ERR("PIN code is not 16 bytes long");
2512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002513 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002514 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002515 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2516 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002517
2518 goto failed;
2519 }
2520
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002521 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002522 if (!cmd) {
2523 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002524 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002525 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002526
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002527 cmd->cmd_complete = addr_cmd_complete;
2528
Johan Hedbergd8457692012-02-17 14:24:57 +02002529 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002531 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002532
2533 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2534 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002535 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002536
2537failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002539 return err;
2540}
2541
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002542static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2543 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002544{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002545 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002546
2547 BT_DBG("");
2548
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002549 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002550 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2551 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002552
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002553 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002554
2555 hdev->io_capability = cp->io_capability;
2556
2557 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002558 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002559
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002560 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002561
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002562 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2563 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002564}
2565
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002566static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002567{
2568 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002569 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002570
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002571 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002572 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2573 continue;
2574
Johan Hedberge9a416b2011-02-19 12:05:56 -03002575 if (cmd->user_data != conn)
2576 continue;
2577
2578 return cmd;
2579 }
2580
2581 return NULL;
2582}
2583
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002584static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002585{
2586 struct mgmt_rp_pair_device rp;
2587 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002588 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002589
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002590 bacpy(&rp.addr.bdaddr, &conn->dst);
2591 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002592
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002593 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2594 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002595
2596 /* So we don't get further callbacks for this connection */
2597 conn->connect_cfm_cb = NULL;
2598 conn->security_cfm_cb = NULL;
2599 conn->disconn_cfm_cb = NULL;
2600
David Herrmann76a68ba2013-04-06 20:28:37 +02002601 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002602
2603 /* The device is paired so there is no need to remove
2604 * its connection parameters anymore.
2605 */
2606 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002607
2608 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002609
2610 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002611}
2612
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002613void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2614{
2615 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002616 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002617
2618 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002619 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002620 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002621 mgmt_pending_remove(cmd);
2622 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002623}
2624
Johan Hedberge9a416b2011-02-19 12:05:56 -03002625static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2626{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002627 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002628
2629 BT_DBG("status %u", status);
2630
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002631 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002632 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002633 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002634 return;
2635 }
2636
2637 cmd->cmd_complete(cmd, mgmt_status(status));
2638 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002639}
2640
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002641static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302642{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002643 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302644
2645 BT_DBG("status %u", status);
2646
2647 if (!status)
2648 return;
2649
2650 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002651 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302652 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002653 return;
2654 }
2655
2656 cmd->cmd_complete(cmd, mgmt_status(status));
2657 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302658}
2659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002660static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002662{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002663 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002664 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002665 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002666 u8 sec_level, auth_type;
2667 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002668 int err;
2669
2670 BT_DBG("");
2671
Szymon Jancf950a30e2013-01-18 12:48:07 +01002672 memset(&rp, 0, sizeof(rp));
2673 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2674 rp.addr.type = cp->addr.type;
2675
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002676 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002677 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2678 MGMT_STATUS_INVALID_PARAMS,
2679 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002680
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002681 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002682 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2683 MGMT_STATUS_INVALID_PARAMS,
2684 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002685
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002686 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002687
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002688 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002689 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2690 MGMT_STATUS_NOT_POWERED, &rp,
2691 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002692 goto unlock;
2693 }
2694
Johan Hedberg55e76b32015-03-10 22:34:40 +02002695 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2696 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2697 MGMT_STATUS_ALREADY_PAIRED, &rp,
2698 sizeof(rp));
2699 goto unlock;
2700 }
2701
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002702 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002703 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002704
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002705 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002706 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2707 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002708 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002709 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002710 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002711
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002712 /* When pairing a new device, it is expected to remember
2713 * this device for future connections. Adding the connection
2714 * parameter information ahead of time allows tracking
2715 * of the slave preferred values and will speed up any
2716 * further connection establishment.
2717 *
2718 * If connection parameters already exist, then they
2719 * will be kept and this function does nothing.
2720 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002721 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2722
2723 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2724 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002725
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002726 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2727 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002728 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002729 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002730
Ville Tervo30e76272011-02-22 16:10:53 -03002731 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002732 int status;
2733
2734 if (PTR_ERR(conn) == -EBUSY)
2735 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002736 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2737 status = MGMT_STATUS_NOT_SUPPORTED;
2738 else if (PTR_ERR(conn) == -ECONNREFUSED)
2739 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002740 else
2741 status = MGMT_STATUS_CONNECT_FAILED;
2742
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002743 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2744 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002745 goto unlock;
2746 }
2747
2748 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002749 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002750 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2751 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002752 goto unlock;
2753 }
2754
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002755 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002756 if (!cmd) {
2757 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002758 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002759 goto unlock;
2760 }
2761
Johan Hedberg04ab2742014-12-05 13:36:04 +02002762 cmd->cmd_complete = pairing_complete;
2763
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002764 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002765 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002766 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002767 conn->security_cfm_cb = pairing_complete_cb;
2768 conn->disconn_cfm_cb = pairing_complete_cb;
2769 } else {
2770 conn->connect_cfm_cb = le_pairing_complete_cb;
2771 conn->security_cfm_cb = le_pairing_complete_cb;
2772 conn->disconn_cfm_cb = le_pairing_complete_cb;
2773 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002774
Johan Hedberge9a416b2011-02-19 12:05:56 -03002775 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002776 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002777
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002778 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002779 hci_conn_security(conn, sec_level, auth_type, true)) {
2780 cmd->cmd_complete(cmd, 0);
2781 mgmt_pending_remove(cmd);
2782 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002783
2784 err = 0;
2785
2786unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002787 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002788 return err;
2789}
2790
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002791static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2792 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002793{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002794 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002795 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002796 struct hci_conn *conn;
2797 int err;
2798
2799 BT_DBG("");
2800
Johan Hedberg28424702012-02-02 04:02:29 +02002801 hci_dev_lock(hdev);
2802
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002803 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002804 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2805 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002806 goto unlock;
2807 }
2808
Johan Hedberg333ae952015-03-17 13:48:47 +02002809 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002810 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002811 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2812 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002813 goto unlock;
2814 }
2815
2816 conn = cmd->user_data;
2817
2818 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002819 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2820 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002821 goto unlock;
2822 }
2823
Johan Hedberga511b352014-12-11 21:45:45 +02002824 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2825 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002826
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002827 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2828 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002829unlock:
2830 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002831 return err;
2832}
2833
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002834static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002835 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002836 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002837{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002838 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002839 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002840 int err;
2841
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002842 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002843
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002844 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002845 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2846 MGMT_STATUS_NOT_POWERED, addr,
2847 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002848 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002849 }
2850
Johan Hedberg1707c602013-03-15 17:07:15 -05002851 if (addr->type == BDADDR_BREDR)
2852 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002853 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002854 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2855 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002856
Johan Hedberg272d90d2012-02-09 15:26:12 +02002857 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002858 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2859 MGMT_STATUS_NOT_CONNECTED, addr,
2860 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002861 goto done;
2862 }
2863
Johan Hedberg1707c602013-03-15 17:07:15 -05002864 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002865 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002866 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002867 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2868 MGMT_STATUS_SUCCESS, addr,
2869 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002870 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002871 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2872 MGMT_STATUS_FAILED, addr,
2873 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002874
Brian Gix47c15e22011-11-16 13:53:14 -08002875 goto done;
2876 }
2877
Johan Hedberg1707c602013-03-15 17:07:15 -05002878 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002879 if (!cmd) {
2880 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002881 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002882 }
2883
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002884 cmd->cmd_complete = addr_cmd_complete;
2885
Brian Gix0df4c182011-11-16 13:53:13 -08002886 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002887 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2888 struct hci_cp_user_passkey_reply cp;
2889
Johan Hedberg1707c602013-03-15 17:07:15 -05002890 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002891 cp.passkey = passkey;
2892 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2893 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002894 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2895 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002896
Johan Hedberga664b5b2011-02-19 12:06:02 -03002897 if (err < 0)
2898 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002899
Brian Gix0df4c182011-11-16 13:53:13 -08002900done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002901 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002902 return err;
2903}
2904
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302905static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2906 void *data, u16 len)
2907{
2908 struct mgmt_cp_pin_code_neg_reply *cp = data;
2909
2910 BT_DBG("");
2911
Johan Hedberg1707c602013-03-15 17:07:15 -05002912 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302913 MGMT_OP_PIN_CODE_NEG_REPLY,
2914 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2915}
2916
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2918 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002919{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002920 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002921
2922 BT_DBG("");
2923
2924 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002925 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2926 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002927
Johan Hedberg1707c602013-03-15 17:07:15 -05002928 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929 MGMT_OP_USER_CONFIRM_REPLY,
2930 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002931}
2932
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002933static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002934 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002935{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002936 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002937
2938 BT_DBG("");
2939
Johan Hedberg1707c602013-03-15 17:07:15 -05002940 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002941 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2942 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002943}
2944
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002945static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2946 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002947{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002948 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002949
2950 BT_DBG("");
2951
Johan Hedberg1707c602013-03-15 17:07:15 -05002952 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002953 MGMT_OP_USER_PASSKEY_REPLY,
2954 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002955}
2956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002957static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002959{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002960 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002961
2962 BT_DBG("");
2963
Johan Hedberg1707c602013-03-15 17:07:15 -05002964 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002965 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2966 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002967}
2968
Marcel Holtmann1904a852015-01-11 13:50:44 -08002969static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05002970{
2971 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002972 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05002973
2974 BT_DBG("status 0x%02x", status);
2975
2976 hci_dev_lock(hdev);
2977
Johan Hedberg333ae952015-03-17 13:48:47 +02002978 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05002979 if (!cmd)
2980 goto unlock;
2981
2982 cp = cmd->param;
2983
2984 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002985 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2986 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05002987 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002988 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2989 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05002990
2991 mgmt_pending_remove(cmd);
2992
2993unlock:
2994 hci_dev_unlock(hdev);
2995}
2996
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002997static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002998 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002999{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003000 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003001 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003002 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003003 int err;
3004
3005 BT_DBG("");
3006
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003007 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003008
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003009 /* If the old values are the same as the new ones just return a
3010 * direct command complete event.
3011 */
3012 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3013 !memcmp(hdev->short_name, cp->short_name,
3014 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003015 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3016 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003017 goto failed;
3018 }
3019
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003020 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003021
Johan Hedbergb5235a62012-02-21 14:32:24 +02003022 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003023 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003024
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003025 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3026 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003027 if (err < 0)
3028 goto failed;
3029
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003030 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3031 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003032
Johan Hedbergb5235a62012-02-21 14:32:24 +02003033 goto failed;
3034 }
3035
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003036 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003037 if (!cmd) {
3038 err = -ENOMEM;
3039 goto failed;
3040 }
3041
Johan Hedberg13928972013-03-15 17:07:00 -05003042 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3043
Johan Hedberg890ea892013-03-15 17:06:52 -05003044 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003045
3046 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003047 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003048 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003049 }
3050
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003051 /* The name is stored in the scan response data and so
3052 * no need to udpate the advertising data here.
3053 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003054 if (lmp_le_capable(hdev))
Johan Hedbergf2252572015-11-18 12:49:20 +02003055 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Johan Hedberg3f985052013-03-15 17:07:02 -05003056
Johan Hedberg13928972013-03-15 17:07:00 -05003057 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003058 if (err < 0)
3059 mgmt_pending_remove(cmd);
3060
3061failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003062 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003063 return err;
3064}
3065
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003066static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3067 u16 opcode, struct sk_buff *skb)
3068{
3069 struct mgmt_rp_read_local_oob_data mgmt_rp;
3070 size_t rp_size = sizeof(mgmt_rp);
3071 struct mgmt_pending_cmd *cmd;
3072
3073 BT_DBG("%s status %u", hdev->name, status);
3074
3075 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3076 if (!cmd)
3077 return;
3078
3079 if (status || !skb) {
3080 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3081 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3082 goto remove;
3083 }
3084
3085 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3086
3087 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3088 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3089
3090 if (skb->len < sizeof(*rp)) {
3091 mgmt_cmd_status(cmd->sk, hdev->id,
3092 MGMT_OP_READ_LOCAL_OOB_DATA,
3093 MGMT_STATUS_FAILED);
3094 goto remove;
3095 }
3096
3097 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3098 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3099
3100 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3101 } else {
3102 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3103
3104 if (skb->len < sizeof(*rp)) {
3105 mgmt_cmd_status(cmd->sk, hdev->id,
3106 MGMT_OP_READ_LOCAL_OOB_DATA,
3107 MGMT_STATUS_FAILED);
3108 goto remove;
3109 }
3110
3111 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3112 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3113
3114 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3115 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3116 }
3117
3118 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3119 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3120
3121remove:
3122 mgmt_pending_remove(cmd);
3123}
3124
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003125static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003127{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003128 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003129 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003130 int err;
3131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003132 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003133
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003134 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003135
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003136 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003137 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3138 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003139 goto unlock;
3140 }
3141
Andre Guedes9a1a1992012-07-24 15:03:48 -03003142 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003143 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3144 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003145 goto unlock;
3146 }
3147
Johan Hedberg333ae952015-03-17 13:48:47 +02003148 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003149 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3150 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003151 goto unlock;
3152 }
3153
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003154 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003155 if (!cmd) {
3156 err = -ENOMEM;
3157 goto unlock;
3158 }
3159
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003160 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003161
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003162 if (bredr_sc_enabled(hdev))
3163 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3164 else
3165 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3166
3167 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003168 if (err < 0)
3169 mgmt_pending_remove(cmd);
3170
3171unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003172 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003173 return err;
3174}
3175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003176static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003177 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003178{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003179 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003180 int err;
3181
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003182 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003183
Johan Hedberg5d57e792015-01-23 10:10:38 +02003184 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003185 return mgmt_cmd_complete(sk, hdev->id,
3186 MGMT_OP_ADD_REMOTE_OOB_DATA,
3187 MGMT_STATUS_INVALID_PARAMS,
3188 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003190 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003191
Marcel Holtmannec109112014-01-10 02:07:30 -08003192 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3193 struct mgmt_cp_add_remote_oob_data *cp = data;
3194 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003195
Johan Hedbergc19a4952014-11-17 20:52:19 +02003196 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003197 err = mgmt_cmd_complete(sk, hdev->id,
3198 MGMT_OP_ADD_REMOTE_OOB_DATA,
3199 MGMT_STATUS_INVALID_PARAMS,
3200 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003201 goto unlock;
3202 }
3203
Marcel Holtmannec109112014-01-10 02:07:30 -08003204 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003205 cp->addr.type, cp->hash,
3206 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003207 if (err < 0)
3208 status = MGMT_STATUS_FAILED;
3209 else
3210 status = MGMT_STATUS_SUCCESS;
3211
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003212 err = mgmt_cmd_complete(sk, hdev->id,
3213 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3214 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003215 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3216 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003217 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003218 u8 status;
3219
Johan Hedberg86df9202014-10-26 20:52:27 +01003220 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003221 /* Enforce zero-valued 192-bit parameters as
3222 * long as legacy SMP OOB isn't implemented.
3223 */
3224 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3225 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003226 err = mgmt_cmd_complete(sk, hdev->id,
3227 MGMT_OP_ADD_REMOTE_OOB_DATA,
3228 MGMT_STATUS_INVALID_PARAMS,
3229 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003230 goto unlock;
3231 }
3232
Johan Hedberg86df9202014-10-26 20:52:27 +01003233 rand192 = NULL;
3234 hash192 = NULL;
3235 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003236 /* In case one of the P-192 values is set to zero,
3237 * then just disable OOB data for P-192.
3238 */
3239 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3240 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3241 rand192 = NULL;
3242 hash192 = NULL;
3243 } else {
3244 rand192 = cp->rand192;
3245 hash192 = cp->hash192;
3246 }
3247 }
3248
3249 /* In case one of the P-256 values is set to zero, then just
3250 * disable OOB data for P-256.
3251 */
3252 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3253 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3254 rand256 = NULL;
3255 hash256 = NULL;
3256 } else {
3257 rand256 = cp->rand256;
3258 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003259 }
3260
Johan Hedberg81328d52014-10-26 20:33:47 +01003261 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003262 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003263 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003264 if (err < 0)
3265 status = MGMT_STATUS_FAILED;
3266 else
3267 status = MGMT_STATUS_SUCCESS;
3268
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003269 err = mgmt_cmd_complete(sk, hdev->id,
3270 MGMT_OP_ADD_REMOTE_OOB_DATA,
3271 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003272 } else {
3273 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003274 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3275 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003276 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003277
Johan Hedbergc19a4952014-11-17 20:52:19 +02003278unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003279 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003280 return err;
3281}
3282
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003283static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003284 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003285{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003286 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003287 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003288 int err;
3289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003290 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003291
Johan Hedbergc19a4952014-11-17 20:52:19 +02003292 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003293 return mgmt_cmd_complete(sk, hdev->id,
3294 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3295 MGMT_STATUS_INVALID_PARAMS,
3296 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003297
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003298 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003299
Johan Hedbergeedbd582014-11-15 09:34:23 +02003300 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3301 hci_remote_oob_data_clear(hdev);
3302 status = MGMT_STATUS_SUCCESS;
3303 goto done;
3304 }
3305
Johan Hedberg6928a922014-10-26 20:46:09 +01003306 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003307 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003308 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003309 else
Szymon Janca6785be2012-12-13 15:11:21 +01003310 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003311
Johan Hedbergeedbd582014-11-15 09:34:23 +02003312done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003313 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3314 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003315
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003316 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003317 return err;
3318}
3319
Johan Hedberge68f0722015-11-11 08:30:30 +02003320void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003321{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003322 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003323
Andre Guedes7c307722013-04-30 15:29:28 -03003324 BT_DBG("status %d", status);
3325
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003326 hci_dev_lock(hdev);
3327
Johan Hedberg333ae952015-03-17 13:48:47 +02003328 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003329 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003330 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003331
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003332 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003333 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003334 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003335 }
3336
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003337 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003338}
3339
Johan Hedberg591752a2015-11-11 08:11:24 +02003340static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3341 uint8_t *mgmt_status)
3342{
3343 switch (type) {
3344 case DISCOV_TYPE_LE:
3345 *mgmt_status = mgmt_le_support(hdev);
3346 if (*mgmt_status)
3347 return false;
3348 break;
3349 case DISCOV_TYPE_INTERLEAVED:
3350 *mgmt_status = mgmt_le_support(hdev);
3351 if (*mgmt_status)
3352 return false;
3353 /* Intentional fall-through */
3354 case DISCOV_TYPE_BREDR:
3355 *mgmt_status = mgmt_bredr_support(hdev);
3356 if (*mgmt_status)
3357 return false;
3358 break;
3359 default:
3360 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3361 return false;
3362 }
3363
3364 return true;
3365}
3366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003367static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003368 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003369{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003370 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003371 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003372 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003373 int err;
3374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003375 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003376
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003377 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003378
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003379 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003380 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3381 MGMT_STATUS_NOT_POWERED,
3382 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003383 goto failed;
3384 }
3385
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003386 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003387 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003388 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3389 MGMT_STATUS_BUSY, &cp->type,
3390 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003391 goto failed;
3392 }
3393
Johan Hedberg591752a2015-11-11 08:11:24 +02003394 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3395 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3396 status, &cp->type, sizeof(cp->type));
3397 goto failed;
3398 }
3399
Marcel Holtmann22078802014-12-05 11:45:22 +01003400 /* Clear the discovery filter first to free any previously
3401 * allocated memory for the UUID list.
3402 */
3403 hci_discovery_filter_clear(hdev);
3404
Andre Guedes4aab14e2012-02-17 20:39:36 -03003405 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003406 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003407
Johan Hedberge68f0722015-11-11 08:30:30 +02003408 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
3409 if (!cmd) {
3410 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003411 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003412 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003413
Johan Hedberge68f0722015-11-11 08:30:30 +02003414 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003415
3416 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003417 queue_work(hdev->req_workqueue, &hdev->discov_update);
3418 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003419
3420failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003421 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003422 return err;
3423}
3424
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003425static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3426 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003427{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003428 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3429 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003430}
3431
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003432static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3433 void *data, u16 len)
3434{
3435 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003436 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003437 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3438 u16 uuid_count, expected_len;
3439 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003440 int err;
3441
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003442 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003443
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003444 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003445
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003446 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003447 err = mgmt_cmd_complete(sk, hdev->id,
3448 MGMT_OP_START_SERVICE_DISCOVERY,
3449 MGMT_STATUS_NOT_POWERED,
3450 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003451 goto failed;
3452 }
3453
3454 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003455 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003456 err = mgmt_cmd_complete(sk, hdev->id,
3457 MGMT_OP_START_SERVICE_DISCOVERY,
3458 MGMT_STATUS_BUSY, &cp->type,
3459 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003460 goto failed;
3461 }
3462
3463 uuid_count = __le16_to_cpu(cp->uuid_count);
3464 if (uuid_count > max_uuid_count) {
3465 BT_ERR("service_discovery: too big uuid_count value %u",
3466 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003467 err = mgmt_cmd_complete(sk, hdev->id,
3468 MGMT_OP_START_SERVICE_DISCOVERY,
3469 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3470 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003471 goto failed;
3472 }
3473
3474 expected_len = sizeof(*cp) + uuid_count * 16;
3475 if (expected_len != len) {
3476 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3477 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003478 err = mgmt_cmd_complete(sk, hdev->id,
3479 MGMT_OP_START_SERVICE_DISCOVERY,
3480 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3481 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003482 goto failed;
3483 }
3484
Johan Hedberg591752a2015-11-11 08:11:24 +02003485 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3486 err = mgmt_cmd_complete(sk, hdev->id,
3487 MGMT_OP_START_SERVICE_DISCOVERY,
3488 status, &cp->type, sizeof(cp->type));
3489 goto failed;
3490 }
3491
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003492 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003493 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003494 if (!cmd) {
3495 err = -ENOMEM;
3496 goto failed;
3497 }
3498
Johan Hedberg2922a942014-12-05 13:36:06 +02003499 cmd->cmd_complete = service_discovery_cmd_complete;
3500
Marcel Holtmann22078802014-12-05 11:45:22 +01003501 /* Clear the discovery filter first to free any previously
3502 * allocated memory for the UUID list.
3503 */
3504 hci_discovery_filter_clear(hdev);
3505
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003506 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003507 hdev->discovery.type = cp->type;
3508 hdev->discovery.rssi = cp->rssi;
3509 hdev->discovery.uuid_count = uuid_count;
3510
3511 if (uuid_count > 0) {
3512 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3513 GFP_KERNEL);
3514 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003515 err = mgmt_cmd_complete(sk, hdev->id,
3516 MGMT_OP_START_SERVICE_DISCOVERY,
3517 MGMT_STATUS_FAILED,
3518 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003519 mgmt_pending_remove(cmd);
3520 goto failed;
3521 }
3522 }
3523
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003524 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003525 queue_work(hdev->req_workqueue, &hdev->discov_update);
3526 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003527
3528failed:
3529 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003530 return err;
3531}
3532
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003533void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003534{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003535 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003536
Andre Guedes0e05bba2013-04-30 15:29:33 -03003537 BT_DBG("status %d", status);
3538
3539 hci_dev_lock(hdev);
3540
Johan Hedberg333ae952015-03-17 13:48:47 +02003541 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003542 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003543 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003544 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003545 }
3546
Andre Guedes0e05bba2013-04-30 15:29:33 -03003547 hci_dev_unlock(hdev);
3548}
3549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003550static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003551 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003552{
Johan Hedbergd9306502012-02-20 23:25:18 +02003553 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003554 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003555 int err;
3556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003557 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003559 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003560
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003561 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003562 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3563 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3564 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003565 goto unlock;
3566 }
3567
3568 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003569 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3570 MGMT_STATUS_INVALID_PARAMS,
3571 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003572 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003573 }
3574
Johan Hedberg2922a942014-12-05 13:36:06 +02003575 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003576 if (!cmd) {
3577 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003578 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003579 }
3580
Johan Hedberg2922a942014-12-05 13:36:06 +02003581 cmd->cmd_complete = generic_cmd_complete;
3582
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003583 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3584 queue_work(hdev->req_workqueue, &hdev->discov_update);
3585 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003586
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003587unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003588 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003589 return err;
3590}
3591
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003592static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003593 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003594{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003595 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003596 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003597 int err;
3598
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003599 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003600
Johan Hedberg561aafb2012-01-04 13:31:59 +02003601 hci_dev_lock(hdev);
3602
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003603 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003604 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3605 MGMT_STATUS_FAILED, &cp->addr,
3606 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003607 goto failed;
3608 }
3609
Johan Hedberga198e7b2012-02-17 14:27:06 +02003610 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003611 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003612 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3613 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3614 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003615 goto failed;
3616 }
3617
3618 if (cp->name_known) {
3619 e->name_state = NAME_KNOWN;
3620 list_del(&e->list);
3621 } else {
3622 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003623 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003624 }
3625
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003626 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3627 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003628
3629failed:
3630 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003631 return err;
3632}
3633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003634static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003635 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003636{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003637 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003638 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003639 int err;
3640
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003641 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003642
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003643 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003644 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3645 MGMT_STATUS_INVALID_PARAMS,
3646 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003647
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003648 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003649
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003650 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3651 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003652 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003653 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003654 goto done;
3655 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003656
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003657 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3658 sk);
3659 status = MGMT_STATUS_SUCCESS;
3660
3661done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003662 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3663 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003665 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003666
3667 return err;
3668}
3669
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003670static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003671 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003672{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003673 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003674 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003675 int err;
3676
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003677 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003678
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003679 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003680 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3681 MGMT_STATUS_INVALID_PARAMS,
3682 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003683
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003684 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003685
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003686 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3687 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003688 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003689 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003690 goto done;
3691 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003692
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003693 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3694 sk);
3695 status = MGMT_STATUS_SUCCESS;
3696
3697done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003698 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3699 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003701 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003702
3703 return err;
3704}
3705
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003706static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3707 u16 len)
3708{
3709 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003710 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003711 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003712 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003713
3714 BT_DBG("%s", hdev->name);
3715
Szymon Jancc72d4b82012-03-16 16:02:57 +01003716 source = __le16_to_cpu(cp->source);
3717
3718 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003719 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3720 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003721
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003722 hci_dev_lock(hdev);
3723
Szymon Jancc72d4b82012-03-16 16:02:57 +01003724 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003725 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3726 hdev->devid_product = __le16_to_cpu(cp->product);
3727 hdev->devid_version = __le16_to_cpu(cp->version);
3728
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003729 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3730 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003731
Johan Hedberg890ea892013-03-15 17:06:52 -05003732 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003733 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003734 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003735
3736 hci_dev_unlock(hdev);
3737
3738 return err;
3739}
3740
Arman Uguray24b4f382015-03-23 15:57:12 -07003741static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3742 u16 opcode)
3743{
3744 BT_DBG("status %d", status);
3745}
3746
Marcel Holtmann1904a852015-01-11 13:50:44 -08003747static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3748 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003749{
3750 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003751 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003752 u8 instance;
3753 struct adv_info *adv_instance;
3754 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003755
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303756 hci_dev_lock(hdev);
3757
Johan Hedberg4375f102013-09-25 13:26:10 +03003758 if (status) {
3759 u8 mgmt_err = mgmt_status(status);
3760
3761 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3762 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303763 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003764 }
3765
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003766 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003767 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003768 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003769 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003770
Johan Hedberg4375f102013-09-25 13:26:10 +03003771 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3772 &match);
3773
3774 new_settings(hdev, match.sk);
3775
3776 if (match.sk)
3777 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303778
Arman Uguray24b4f382015-03-23 15:57:12 -07003779 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003780 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003781 */
3782 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003783 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
3784 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003785 goto unlock;
3786
Florian Grandel7816b822015-06-18 03:16:45 +02003787 instance = hdev->cur_adv_instance;
3788 if (!instance) {
3789 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3790 struct adv_info, list);
3791 if (!adv_instance)
3792 goto unlock;
3793
3794 instance = adv_instance->instance;
3795 }
3796
Arman Uguray24b4f382015-03-23 15:57:12 -07003797 hci_req_init(&req, hdev);
3798
Johan Hedbergf2252572015-11-18 12:49:20 +02003799 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003800
Florian Grandel7816b822015-06-18 03:16:45 +02003801 if (!err)
3802 err = hci_req_run(&req, enable_advertising_instance);
3803
3804 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003805 BT_ERR("Failed to re-configure advertising");
3806
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303807unlock:
3808 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003809}
3810
Marcel Holtmann21b51872013-10-10 09:47:53 -07003811static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3812 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003813{
3814 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003815 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003816 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003817 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003818 int err;
3819
3820 BT_DBG("request for %s", hdev->name);
3821
Johan Hedberge6fe7982013-10-02 15:45:22 +03003822 status = mgmt_le_support(hdev);
3823 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003824 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3825 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003826
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003827 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003828 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3829 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003830
3831 hci_dev_lock(hdev);
3832
3833 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003834
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003835 /* The following conditions are ones which mean that we should
3836 * not do any HCI communication but directly send a mgmt
3837 * response to user space (after toggling the flag if
3838 * necessary).
3839 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003840 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003841 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3842 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003843 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003844 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003845 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003846 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003847
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003848 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07003849 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003850 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003851 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003852 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003853 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003854 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003855 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003856 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003857 }
3858
3859 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3860 if (err < 0)
3861 goto unlock;
3862
3863 if (changed)
3864 err = new_settings(hdev, sk);
3865
3866 goto unlock;
3867 }
3868
Johan Hedberg333ae952015-03-17 13:48:47 +02003869 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3870 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003871 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3872 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03003873 goto unlock;
3874 }
3875
3876 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3877 if (!cmd) {
3878 err = -ENOMEM;
3879 goto unlock;
3880 }
3881
3882 hci_req_init(&req, hdev);
3883
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003884 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003885 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003886 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003887 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003888
Florian Grandel7816b822015-06-18 03:16:45 +02003889 cancel_adv_timeout(hdev);
3890
Arman Uguray24b4f382015-03-23 15:57:12 -07003891 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02003892 /* Switch to instance "0" for the Set Advertising setting.
3893 * We cannot use update_[adv|scan_rsp]_data() here as the
3894 * HCI_ADVERTISING flag is not yet set.
3895 */
Johan Hedbergf2252572015-11-18 12:49:20 +02003896 __hci_req_update_adv_data(&req, 0x00);
3897 __hci_req_update_scan_rsp_data(&req, 0x00);
3898 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003899 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02003900 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003901 }
Johan Hedberg4375f102013-09-25 13:26:10 +03003902
3903 err = hci_req_run(&req, set_advertising_complete);
3904 if (err < 0)
3905 mgmt_pending_remove(cmd);
3906
3907unlock:
3908 hci_dev_unlock(hdev);
3909 return err;
3910}
3911
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003912static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3913 void *data, u16 len)
3914{
3915 struct mgmt_cp_set_static_address *cp = data;
3916 int err;
3917
3918 BT_DBG("%s", hdev->name);
3919
Marcel Holtmann62af4442013-10-02 22:10:32 -07003920 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003921 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3922 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003923
3924 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003925 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3926 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003927
3928 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3929 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02003930 return mgmt_cmd_status(sk, hdev->id,
3931 MGMT_OP_SET_STATIC_ADDRESS,
3932 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003933
3934 /* Two most significant bits shall be set */
3935 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003936 return mgmt_cmd_status(sk, hdev->id,
3937 MGMT_OP_SET_STATIC_ADDRESS,
3938 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003939 }
3940
3941 hci_dev_lock(hdev);
3942
3943 bacpy(&hdev->static_addr, &cp->bdaddr);
3944
Marcel Holtmann93690c22015-03-06 10:11:21 -08003945 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
3946 if (err < 0)
3947 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003948
Marcel Holtmann93690c22015-03-06 10:11:21 -08003949 err = new_settings(hdev, sk);
3950
3951unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003952 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003953 return err;
3954}
3955
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003956static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3957 void *data, u16 len)
3958{
3959 struct mgmt_cp_set_scan_params *cp = data;
3960 __u16 interval, window;
3961 int err;
3962
3963 BT_DBG("%s", hdev->name);
3964
3965 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003966 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3967 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003968
3969 interval = __le16_to_cpu(cp->interval);
3970
3971 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003972 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3973 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003974
3975 window = __le16_to_cpu(cp->window);
3976
3977 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003978 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3979 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003980
Marcel Holtmann899e1072013-10-14 09:55:32 -07003981 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02003982 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3983 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07003984
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003985 hci_dev_lock(hdev);
3986
3987 hdev->le_scan_interval = interval;
3988 hdev->le_scan_window = window;
3989
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003990 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
3991 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003992
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003993 /* If background scan is running, restart it so new parameters are
3994 * loaded.
3995 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003996 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003997 hdev->discovery.state == DISCOVERY_STOPPED) {
3998 struct hci_request req;
3999
4000 hci_req_init(&req, hdev);
4001
4002 hci_req_add_le_scan_disable(&req);
4003 hci_req_add_le_passive_scan(&req);
4004
4005 hci_req_run(&req, NULL);
4006 }
4007
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004008 hci_dev_unlock(hdev);
4009
4010 return err;
4011}
4012
Marcel Holtmann1904a852015-01-11 13:50:44 -08004013static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4014 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004015{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004016 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004017
4018 BT_DBG("status 0x%02x", status);
4019
4020 hci_dev_lock(hdev);
4021
Johan Hedberg333ae952015-03-17 13:48:47 +02004022 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004023 if (!cmd)
4024 goto unlock;
4025
4026 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004027 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4028 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004029 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004030 struct mgmt_mode *cp = cmd->param;
4031
4032 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004033 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004034 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004035 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004036
Johan Hedberg33e38b32013-03-15 17:07:05 -05004037 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4038 new_settings(hdev, cmd->sk);
4039 }
4040
4041 mgmt_pending_remove(cmd);
4042
4043unlock:
4044 hci_dev_unlock(hdev);
4045}
4046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004047static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004048 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004049{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004050 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004051 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004052 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004053 int err;
4054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004055 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004056
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004057 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004058 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004059 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4060 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004061
Johan Hedberga7e80f22013-01-09 16:05:19 +02004062 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004063 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4064 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004065
Antti Julkuf6422ec2011-06-22 13:11:56 +03004066 hci_dev_lock(hdev);
4067
Johan Hedberg333ae952015-03-17 13:48:47 +02004068 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004069 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4070 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004071 goto unlock;
4072 }
4073
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004074 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004075 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4076 hdev);
4077 goto unlock;
4078 }
4079
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004080 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004081 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004082 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4083 hdev);
4084 new_settings(hdev, sk);
4085 goto unlock;
4086 }
4087
Johan Hedberg33e38b32013-03-15 17:07:05 -05004088 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4089 data, len);
4090 if (!cmd) {
4091 err = -ENOMEM;
4092 goto unlock;
4093 }
4094
4095 hci_req_init(&req, hdev);
4096
Johan Hedberg406d7802013-03-15 17:07:09 -05004097 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004098
4099 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004100 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004101 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4102 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004103 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004104 }
4105
Johan Hedberg33e38b32013-03-15 17:07:05 -05004106unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004107 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004108
Antti Julkuf6422ec2011-06-22 13:11:56 +03004109 return err;
4110}
4111
Marcel Holtmann1904a852015-01-11 13:50:44 -08004112static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004113{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004114 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004115
4116 BT_DBG("status 0x%02x", status);
4117
4118 hci_dev_lock(hdev);
4119
Johan Hedberg333ae952015-03-17 13:48:47 +02004120 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004121 if (!cmd)
4122 goto unlock;
4123
4124 if (status) {
4125 u8 mgmt_err = mgmt_status(status);
4126
4127 /* We need to restore the flag if related HCI commands
4128 * failed.
4129 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004130 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004131
Johan Hedberga69e8372015-03-06 21:08:53 +02004132 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004133 } else {
4134 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4135 new_settings(hdev, cmd->sk);
4136 }
4137
4138 mgmt_pending_remove(cmd);
4139
4140unlock:
4141 hci_dev_unlock(hdev);
4142}
4143
4144static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4145{
4146 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004147 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004148 struct hci_request req;
4149 int err;
4150
4151 BT_DBG("request for %s", hdev->name);
4152
4153 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004154 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4155 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004156
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004157 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004158 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4159 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004160
4161 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004162 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4163 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004164
4165 hci_dev_lock(hdev);
4166
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004167 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004168 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4169 goto unlock;
4170 }
4171
4172 if (!hdev_is_powered(hdev)) {
4173 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004174 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4175 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4176 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4177 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4178 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004179 }
4180
Marcel Holtmannce05d602015-03-13 02:11:03 -07004181 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004182
4183 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4184 if (err < 0)
4185 goto unlock;
4186
4187 err = new_settings(hdev, sk);
4188 goto unlock;
4189 }
4190
4191 /* Reject disabling when powered on */
4192 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004193 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4194 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004195 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004196 } else {
4197 /* When configuring a dual-mode controller to operate
4198 * with LE only and using a static address, then switching
4199 * BR/EDR back on is not allowed.
4200 *
4201 * Dual-mode controllers shall operate with the public
4202 * address as its identity address for BR/EDR and LE. So
4203 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004204 *
4205 * The same restrictions applies when secure connections
4206 * has been enabled. For BR/EDR this is a controller feature
4207 * while for LE it is a host stack feature. This means that
4208 * switching BR/EDR back on when secure connections has been
4209 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004210 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004211 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004212 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004213 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004214 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4215 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004216 goto unlock;
4217 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004218 }
4219
Johan Hedberg333ae952015-03-17 13:48:47 +02004220 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004221 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4222 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004223 goto unlock;
4224 }
4225
4226 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4227 if (!cmd) {
4228 err = -ENOMEM;
4229 goto unlock;
4230 }
4231
Johan Hedbergf2252572015-11-18 12:49:20 +02004232 /* We need to flip the bit already here so that
4233 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004234 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004235 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004236
4237 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004238
Johan Hedberg432df052014-08-01 11:13:31 +03004239 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004240 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004241
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004242 /* Since only the advertising data flags will change, there
4243 * is no need to update the scan response data.
4244 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004245 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004246
Johan Hedberg0663ca22013-10-02 13:43:14 +03004247 err = hci_req_run(&req, set_bredr_complete);
4248 if (err < 0)
4249 mgmt_pending_remove(cmd);
4250
4251unlock:
4252 hci_dev_unlock(hdev);
4253 return err;
4254}
4255
Johan Hedberga1443f52015-01-23 15:42:46 +02004256static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4257{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004258 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004259 struct mgmt_mode *cp;
4260
4261 BT_DBG("%s status %u", hdev->name, status);
4262
4263 hci_dev_lock(hdev);
4264
Johan Hedberg333ae952015-03-17 13:48:47 +02004265 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004266 if (!cmd)
4267 goto unlock;
4268
4269 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004270 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4271 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004272 goto remove;
4273 }
4274
4275 cp = cmd->param;
4276
4277 switch (cp->val) {
4278 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004279 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4280 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004281 break;
4282 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004283 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004284 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004285 break;
4286 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004287 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4288 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004289 break;
4290 }
4291
4292 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4293 new_settings(hdev, cmd->sk);
4294
4295remove:
4296 mgmt_pending_remove(cmd);
4297unlock:
4298 hci_dev_unlock(hdev);
4299}
4300
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004301static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4302 void *data, u16 len)
4303{
4304 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004305 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004306 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004307 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004308 int err;
4309
4310 BT_DBG("request for %s", hdev->name);
4311
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004312 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004313 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4315 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004316
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004317 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004318 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004319 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004320 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4321 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004322
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004323 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004324 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004325 MGMT_STATUS_INVALID_PARAMS);
4326
4327 hci_dev_lock(hdev);
4328
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004329 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004330 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004331 bool changed;
4332
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004333 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004334 changed = !hci_dev_test_and_set_flag(hdev,
4335 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004336 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004337 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004338 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004339 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004340 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004341 changed = hci_dev_test_and_clear_flag(hdev,
4342 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004343 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004344 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004345
4346 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4347 if (err < 0)
4348 goto failed;
4349
4350 if (changed)
4351 err = new_settings(hdev, sk);
4352
4353 goto failed;
4354 }
4355
Johan Hedberg333ae952015-03-17 13:48:47 +02004356 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004357 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4358 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004359 goto failed;
4360 }
4361
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004362 val = !!cp->val;
4363
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004364 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4365 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004366 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4367 goto failed;
4368 }
4369
4370 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4371 if (!cmd) {
4372 err = -ENOMEM;
4373 goto failed;
4374 }
4375
Johan Hedberga1443f52015-01-23 15:42:46 +02004376 hci_req_init(&req, hdev);
4377 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4378 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004379 if (err < 0) {
4380 mgmt_pending_remove(cmd);
4381 goto failed;
4382 }
4383
4384failed:
4385 hci_dev_unlock(hdev);
4386 return err;
4387}
4388
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004389static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4390 void *data, u16 len)
4391{
4392 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004393 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004394 int err;
4395
4396 BT_DBG("request for %s", hdev->name);
4397
Johan Hedbergb97109792014-06-24 14:00:28 +03004398 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004399 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4400 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004401
4402 hci_dev_lock(hdev);
4403
4404 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004405 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004406 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004407 changed = hci_dev_test_and_clear_flag(hdev,
4408 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004409
Johan Hedbergb97109792014-06-24 14:00:28 +03004410 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004411 use_changed = !hci_dev_test_and_set_flag(hdev,
4412 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004413 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004414 use_changed = hci_dev_test_and_clear_flag(hdev,
4415 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004416
4417 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004418 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004419 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4420 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4421 sizeof(mode), &mode);
4422 }
4423
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004424 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4425 if (err < 0)
4426 goto unlock;
4427
4428 if (changed)
4429 err = new_settings(hdev, sk);
4430
4431unlock:
4432 hci_dev_unlock(hdev);
4433 return err;
4434}
4435
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004436static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4437 u16 len)
4438{
4439 struct mgmt_cp_set_privacy *cp = cp_data;
4440 bool changed;
4441 int err;
4442
4443 BT_DBG("request for %s", hdev->name);
4444
4445 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004446 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4447 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004448
4449 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004450 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4451 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004452
4453 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004454 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4455 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004456
4457 hci_dev_lock(hdev);
4458
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004459 /* If user space supports this command it is also expected to
4460 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4461 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004462 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004463
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004464 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004465 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004466 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004467 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004468 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004469 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004470 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004471 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004472 }
4473
4474 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4475 if (err < 0)
4476 goto unlock;
4477
4478 if (changed)
4479 err = new_settings(hdev, sk);
4480
4481unlock:
4482 hci_dev_unlock(hdev);
4483 return err;
4484}
4485
Johan Hedberg41edf162014-02-18 10:19:35 +02004486static bool irk_is_valid(struct mgmt_irk_info *irk)
4487{
4488 switch (irk->addr.type) {
4489 case BDADDR_LE_PUBLIC:
4490 return true;
4491
4492 case BDADDR_LE_RANDOM:
4493 /* Two most significant bits shall be set */
4494 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4495 return false;
4496 return true;
4497 }
4498
4499 return false;
4500}
4501
4502static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4503 u16 len)
4504{
4505 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004506 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4507 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004508 u16 irk_count, expected_len;
4509 int i, err;
4510
4511 BT_DBG("request for %s", hdev->name);
4512
4513 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004514 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4515 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004516
4517 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004518 if (irk_count > max_irk_count) {
4519 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004520 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4521 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004522 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004523
4524 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4525 if (expected_len != len) {
4526 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004527 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004528 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4529 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004530 }
4531
4532 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4533
4534 for (i = 0; i < irk_count; i++) {
4535 struct mgmt_irk_info *key = &cp->irks[i];
4536
4537 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004538 return mgmt_cmd_status(sk, hdev->id,
4539 MGMT_OP_LOAD_IRKS,
4540 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004541 }
4542
4543 hci_dev_lock(hdev);
4544
4545 hci_smp_irks_clear(hdev);
4546
4547 for (i = 0; i < irk_count; i++) {
4548 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004549
Johan Hedberg85813a72015-10-21 18:02:59 +03004550 hci_add_irk(hdev, &irk->addr.bdaddr,
4551 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004552 BDADDR_ANY);
4553 }
4554
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004555 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004556
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004557 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004558
4559 hci_dev_unlock(hdev);
4560
4561 return err;
4562}
4563
Johan Hedberg3f706b72013-01-20 14:27:16 +02004564static bool ltk_is_valid(struct mgmt_ltk_info *key)
4565{
4566 if (key->master != 0x00 && key->master != 0x01)
4567 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004568
4569 switch (key->addr.type) {
4570 case BDADDR_LE_PUBLIC:
4571 return true;
4572
4573 case BDADDR_LE_RANDOM:
4574 /* Two most significant bits shall be set */
4575 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4576 return false;
4577 return true;
4578 }
4579
4580 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004581}
4582
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004583static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004584 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004585{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004586 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004587 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4588 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004589 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004590 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004591
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004592 BT_DBG("request for %s", hdev->name);
4593
4594 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004595 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4596 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004597
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004598 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004599 if (key_count > max_key_count) {
4600 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004601 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4602 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004603 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004604
4605 expected_len = sizeof(*cp) + key_count *
4606 sizeof(struct mgmt_ltk_info);
4607 if (expected_len != len) {
4608 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004609 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004610 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4611 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004612 }
4613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004614 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004615
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004616 for (i = 0; i < key_count; i++) {
4617 struct mgmt_ltk_info *key = &cp->keys[i];
4618
Johan Hedberg3f706b72013-01-20 14:27:16 +02004619 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004620 return mgmt_cmd_status(sk, hdev->id,
4621 MGMT_OP_LOAD_LONG_TERM_KEYS,
4622 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004623 }
4624
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004625 hci_dev_lock(hdev);
4626
4627 hci_smp_ltks_clear(hdev);
4628
4629 for (i = 0; i < key_count; i++) {
4630 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004631 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004632
Johan Hedberg61b43352014-05-29 19:36:53 +03004633 switch (key->type) {
4634 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004635 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004636 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004637 break;
4638 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004639 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004640 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004641 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004642 case MGMT_LTK_P256_UNAUTH:
4643 authenticated = 0x00;
4644 type = SMP_LTK_P256;
4645 break;
4646 case MGMT_LTK_P256_AUTH:
4647 authenticated = 0x01;
4648 type = SMP_LTK_P256;
4649 break;
4650 case MGMT_LTK_P256_DEBUG:
4651 authenticated = 0x00;
4652 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004653 default:
4654 continue;
4655 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004656
Johan Hedberg85813a72015-10-21 18:02:59 +03004657 hci_add_ltk(hdev, &key->addr.bdaddr,
4658 le_addr_type(key->addr.type), type, authenticated,
4659 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004660 }
4661
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004662 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004663 NULL, 0);
4664
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004665 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004666
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004667 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004668}
4669
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004670static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004671{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004672 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004673 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004674 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004675
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004676 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004677
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004678 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004679 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004680 rp.tx_power = conn->tx_power;
4681 rp.max_tx_power = conn->max_tx_power;
4682 } else {
4683 rp.rssi = HCI_RSSI_INVALID;
4684 rp.tx_power = HCI_TX_POWER_INVALID;
4685 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004686 }
4687
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004688 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4689 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004690
4691 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004692 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004693
4694 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004695}
4696
Marcel Holtmann1904a852015-01-11 13:50:44 -08004697static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4698 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004699{
4700 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004701 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004702 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004703 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004704 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004705
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004706 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004707
4708 hci_dev_lock(hdev);
4709
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004710 /* Commands sent in request are either Read RSSI or Read Transmit Power
4711 * Level so we check which one was last sent to retrieve connection
4712 * handle. Both commands have handle as first parameter so it's safe to
4713 * cast data on the same command struct.
4714 *
4715 * First command sent is always Read RSSI and we fail only if it fails.
4716 * In other case we simply override error to indicate success as we
4717 * already remembered if TX power value is actually valid.
4718 */
4719 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4720 if (!cp) {
4721 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004722 status = MGMT_STATUS_SUCCESS;
4723 } else {
4724 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004725 }
4726
4727 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004728 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004729 goto unlock;
4730 }
4731
4732 handle = __le16_to_cpu(cp->handle);
4733 conn = hci_conn_hash_lookup_handle(hdev, handle);
4734 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004735 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004736 goto unlock;
4737 }
4738
Johan Hedberg333ae952015-03-17 13:48:47 +02004739 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004740 if (!cmd)
4741 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004742
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004743 cmd->cmd_complete(cmd, status);
4744 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004745
4746unlock:
4747 hci_dev_unlock(hdev);
4748}
4749
4750static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4751 u16 len)
4752{
4753 struct mgmt_cp_get_conn_info *cp = data;
4754 struct mgmt_rp_get_conn_info rp;
4755 struct hci_conn *conn;
4756 unsigned long conn_info_age;
4757 int err = 0;
4758
4759 BT_DBG("%s", hdev->name);
4760
4761 memset(&rp, 0, sizeof(rp));
4762 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4763 rp.addr.type = cp->addr.type;
4764
4765 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004766 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4767 MGMT_STATUS_INVALID_PARAMS,
4768 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004769
4770 hci_dev_lock(hdev);
4771
4772 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004773 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4774 MGMT_STATUS_NOT_POWERED, &rp,
4775 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004776 goto unlock;
4777 }
4778
4779 if (cp->addr.type == BDADDR_BREDR)
4780 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4781 &cp->addr.bdaddr);
4782 else
4783 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4784
4785 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004786 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4787 MGMT_STATUS_NOT_CONNECTED, &rp,
4788 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004789 goto unlock;
4790 }
4791
Johan Hedberg333ae952015-03-17 13:48:47 +02004792 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004793 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4794 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004795 goto unlock;
4796 }
4797
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004798 /* To avoid client trying to guess when to poll again for information we
4799 * calculate conn info age as random value between min/max set in hdev.
4800 */
4801 conn_info_age = hdev->conn_info_min_age +
4802 prandom_u32_max(hdev->conn_info_max_age -
4803 hdev->conn_info_min_age);
4804
4805 /* Query controller to refresh cached values if they are too old or were
4806 * never read.
4807 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004808 if (time_after(jiffies, conn->conn_info_timestamp +
4809 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004810 !conn->conn_info_timestamp) {
4811 struct hci_request req;
4812 struct hci_cp_read_tx_power req_txp_cp;
4813 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004814 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004815
4816 hci_req_init(&req, hdev);
4817 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4818 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4819 &req_rssi_cp);
4820
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004821 /* For LE links TX power does not change thus we don't need to
4822 * query for it once value is known.
4823 */
4824 if (!bdaddr_type_is_le(cp->addr.type) ||
4825 conn->tx_power == HCI_TX_POWER_INVALID) {
4826 req_txp_cp.handle = cpu_to_le16(conn->handle);
4827 req_txp_cp.type = 0x00;
4828 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4829 sizeof(req_txp_cp), &req_txp_cp);
4830 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004831
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004832 /* Max TX power needs to be read only once per connection */
4833 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4834 req_txp_cp.handle = cpu_to_le16(conn->handle);
4835 req_txp_cp.type = 0x01;
4836 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4837 sizeof(req_txp_cp), &req_txp_cp);
4838 }
4839
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004840 err = hci_req_run(&req, conn_info_refresh_complete);
4841 if (err < 0)
4842 goto unlock;
4843
4844 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4845 data, len);
4846 if (!cmd) {
4847 err = -ENOMEM;
4848 goto unlock;
4849 }
4850
4851 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004852 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004853 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004854
4855 conn->conn_info_timestamp = jiffies;
4856 } else {
4857 /* Cache is valid, just reply with values cached in hci_conn */
4858 rp.rssi = conn->rssi;
4859 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004860 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004861
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004862 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4863 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004864 }
4865
4866unlock:
4867 hci_dev_unlock(hdev);
4868 return err;
4869}
4870
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004871static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004872{
4873 struct hci_conn *conn = cmd->user_data;
4874 struct mgmt_rp_get_clock_info rp;
4875 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004876 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004877
4878 memset(&rp, 0, sizeof(rp));
4879 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
4880
4881 if (status)
4882 goto complete;
4883
4884 hdev = hci_dev_get(cmd->index);
4885 if (hdev) {
4886 rp.local_clock = cpu_to_le32(hdev->clock);
4887 hci_dev_put(hdev);
4888 }
4889
4890 if (conn) {
4891 rp.piconet_clock = cpu_to_le32(conn->clock);
4892 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
4893 }
4894
4895complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004896 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
4897 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02004898
4899 if (conn) {
4900 hci_conn_drop(conn);
4901 hci_conn_put(conn);
4902 }
Johan Hedberg9df74652014-12-19 22:26:03 +02004903
4904 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02004905}
4906
Marcel Holtmann1904a852015-01-11 13:50:44 -08004907static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03004908{
Johan Hedberg95868422014-06-28 17:54:07 +03004909 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004910 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004911 struct hci_conn *conn;
4912
4913 BT_DBG("%s status %u", hdev->name, status);
4914
4915 hci_dev_lock(hdev);
4916
4917 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
4918 if (!hci_cp)
4919 goto unlock;
4920
4921 if (hci_cp->which) {
4922 u16 handle = __le16_to_cpu(hci_cp->handle);
4923 conn = hci_conn_hash_lookup_handle(hdev, handle);
4924 } else {
4925 conn = NULL;
4926 }
4927
Johan Hedberg333ae952015-03-17 13:48:47 +02004928 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004929 if (!cmd)
4930 goto unlock;
4931
Johan Hedberg69487372014-12-05 13:36:07 +02004932 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03004933 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03004934
4935unlock:
4936 hci_dev_unlock(hdev);
4937}
4938
4939static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
4940 u16 len)
4941{
4942 struct mgmt_cp_get_clock_info *cp = data;
4943 struct mgmt_rp_get_clock_info rp;
4944 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004945 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004946 struct hci_request req;
4947 struct hci_conn *conn;
4948 int err;
4949
4950 BT_DBG("%s", hdev->name);
4951
4952 memset(&rp, 0, sizeof(rp));
4953 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4954 rp.addr.type = cp->addr.type;
4955
4956 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004957 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4958 MGMT_STATUS_INVALID_PARAMS,
4959 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004960
4961 hci_dev_lock(hdev);
4962
4963 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004964 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4965 MGMT_STATUS_NOT_POWERED, &rp,
4966 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004967 goto unlock;
4968 }
4969
4970 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4971 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4972 &cp->addr.bdaddr);
4973 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004974 err = mgmt_cmd_complete(sk, hdev->id,
4975 MGMT_OP_GET_CLOCK_INFO,
4976 MGMT_STATUS_NOT_CONNECTED,
4977 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004978 goto unlock;
4979 }
4980 } else {
4981 conn = NULL;
4982 }
4983
4984 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
4985 if (!cmd) {
4986 err = -ENOMEM;
4987 goto unlock;
4988 }
4989
Johan Hedberg69487372014-12-05 13:36:07 +02004990 cmd->cmd_complete = clock_info_cmd_complete;
4991
Johan Hedberg95868422014-06-28 17:54:07 +03004992 hci_req_init(&req, hdev);
4993
4994 memset(&hci_cp, 0, sizeof(hci_cp));
4995 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4996
4997 if (conn) {
4998 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004999 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005000
5001 hci_cp.handle = cpu_to_le16(conn->handle);
5002 hci_cp.which = 0x01; /* Piconet clock */
5003 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5004 }
5005
5006 err = hci_req_run(&req, get_clock_info_complete);
5007 if (err < 0)
5008 mgmt_pending_remove(cmd);
5009
5010unlock:
5011 hci_dev_unlock(hdev);
5012 return err;
5013}
5014
Johan Hedberg5a154e62014-12-19 22:26:02 +02005015static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5016{
5017 struct hci_conn *conn;
5018
5019 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5020 if (!conn)
5021 return false;
5022
5023 if (conn->dst_type != type)
5024 return false;
5025
5026 if (conn->state != BT_CONNECTED)
5027 return false;
5028
5029 return true;
5030}
5031
5032/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005033static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005034 u8 addr_type, u8 auto_connect)
5035{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005036 struct hci_conn_params *params;
5037
5038 params = hci_conn_params_add(hdev, addr, addr_type);
5039 if (!params)
5040 return -EIO;
5041
5042 if (params->auto_connect == auto_connect)
5043 return 0;
5044
5045 list_del_init(&params->action);
5046
5047 switch (auto_connect) {
5048 case HCI_AUTO_CONN_DISABLED:
5049 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005050 /* If auto connect is being disabled when we're trying to
5051 * connect to device, keep connecting.
5052 */
5053 if (params->explicit_connect)
5054 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005055 break;
5056 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005057 if (params->explicit_connect)
5058 list_add(&params->action, &hdev->pend_le_conns);
5059 else
5060 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005061 break;
5062 case HCI_AUTO_CONN_DIRECT:
5063 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005064 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005065 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005066 break;
5067 }
5068
5069 params->auto_connect = auto_connect;
5070
5071 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5072 auto_connect);
5073
5074 return 0;
5075}
5076
Marcel Holtmann8afef092014-06-29 22:28:34 +02005077static void device_added(struct sock *sk, struct hci_dev *hdev,
5078 bdaddr_t *bdaddr, u8 type, u8 action)
5079{
5080 struct mgmt_ev_device_added ev;
5081
5082 bacpy(&ev.addr.bdaddr, bdaddr);
5083 ev.addr.type = type;
5084 ev.action = action;
5085
5086 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5087}
5088
Marcel Holtmann2faade52014-06-29 19:44:03 +02005089static int add_device(struct sock *sk, struct hci_dev *hdev,
5090 void *data, u16 len)
5091{
5092 struct mgmt_cp_add_device *cp = data;
5093 u8 auto_conn, addr_type;
5094 int err;
5095
5096 BT_DBG("%s", hdev->name);
5097
Johan Hedberg66593582014-07-09 12:59:14 +03005098 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005099 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005100 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5101 MGMT_STATUS_INVALID_PARAMS,
5102 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005103
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005104 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005105 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5106 MGMT_STATUS_INVALID_PARAMS,
5107 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005108
5109 hci_dev_lock(hdev);
5110
Johan Hedberg66593582014-07-09 12:59:14 +03005111 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005112 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005113 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005114 err = mgmt_cmd_complete(sk, hdev->id,
5115 MGMT_OP_ADD_DEVICE,
5116 MGMT_STATUS_INVALID_PARAMS,
5117 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005118 goto unlock;
5119 }
5120
5121 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5122 cp->addr.type);
5123 if (err)
5124 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005125
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005126 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005127
Johan Hedberg66593582014-07-09 12:59:14 +03005128 goto added;
5129 }
5130
Johan Hedberg85813a72015-10-21 18:02:59 +03005131 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005132
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005133 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005134 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005135 else if (cp->action == 0x01)
5136 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005137 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005138 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005139
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005140 /* Kernel internally uses conn_params with resolvable private
5141 * address, but Add Device allows only identity addresses.
5142 * Make sure it is enforced before calling
5143 * hci_conn_params_lookup.
5144 */
5145 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005146 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5147 MGMT_STATUS_INVALID_PARAMS,
5148 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005149 goto unlock;
5150 }
5151
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005152 /* If the connection parameters don't exist for this device,
5153 * they will be created and configured with defaults.
5154 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005155 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005156 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005157 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5158 MGMT_STATUS_FAILED, &cp->addr,
5159 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005160 goto unlock;
5161 }
5162
Johan Hedberg51d7a942015-11-11 08:11:18 +02005163 hci_update_background_scan(hdev);
5164
Johan Hedberg66593582014-07-09 12:59:14 +03005165added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005166 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5167
Johan Hedberg51d7a942015-11-11 08:11:18 +02005168 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5169 MGMT_STATUS_SUCCESS, &cp->addr,
5170 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005171
5172unlock:
5173 hci_dev_unlock(hdev);
5174 return err;
5175}
5176
Marcel Holtmann8afef092014-06-29 22:28:34 +02005177static void device_removed(struct sock *sk, struct hci_dev *hdev,
5178 bdaddr_t *bdaddr, u8 type)
5179{
5180 struct mgmt_ev_device_removed ev;
5181
5182 bacpy(&ev.addr.bdaddr, bdaddr);
5183 ev.addr.type = type;
5184
5185 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5186}
5187
Marcel Holtmann2faade52014-06-29 19:44:03 +02005188static int remove_device(struct sock *sk, struct hci_dev *hdev,
5189 void *data, u16 len)
5190{
5191 struct mgmt_cp_remove_device *cp = data;
5192 int err;
5193
5194 BT_DBG("%s", hdev->name);
5195
5196 hci_dev_lock(hdev);
5197
5198 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005199 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005200 u8 addr_type;
5201
Johan Hedberg66593582014-07-09 12:59:14 +03005202 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005203 err = mgmt_cmd_complete(sk, hdev->id,
5204 MGMT_OP_REMOVE_DEVICE,
5205 MGMT_STATUS_INVALID_PARAMS,
5206 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005207 goto unlock;
5208 }
5209
Johan Hedberg66593582014-07-09 12:59:14 +03005210 if (cp->addr.type == BDADDR_BREDR) {
5211 err = hci_bdaddr_list_del(&hdev->whitelist,
5212 &cp->addr.bdaddr,
5213 cp->addr.type);
5214 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005215 err = mgmt_cmd_complete(sk, hdev->id,
5216 MGMT_OP_REMOVE_DEVICE,
5217 MGMT_STATUS_INVALID_PARAMS,
5218 &cp->addr,
5219 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005220 goto unlock;
5221 }
5222
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005223 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005224
Johan Hedberg66593582014-07-09 12:59:14 +03005225 device_removed(sk, hdev, &cp->addr.bdaddr,
5226 cp->addr.type);
5227 goto complete;
5228 }
5229
Johan Hedberg85813a72015-10-21 18:02:59 +03005230 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005231
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005232 /* Kernel internally uses conn_params with resolvable private
5233 * address, but Remove Device allows only identity addresses.
5234 * Make sure it is enforced before calling
5235 * hci_conn_params_lookup.
5236 */
5237 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005238 err = mgmt_cmd_complete(sk, hdev->id,
5239 MGMT_OP_REMOVE_DEVICE,
5240 MGMT_STATUS_INVALID_PARAMS,
5241 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005242 goto unlock;
5243 }
5244
Johan Hedbergc71593d2014-07-02 17:37:28 +03005245 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5246 addr_type);
5247 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005248 err = mgmt_cmd_complete(sk, hdev->id,
5249 MGMT_OP_REMOVE_DEVICE,
5250 MGMT_STATUS_INVALID_PARAMS,
5251 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005252 goto unlock;
5253 }
5254
Johan Hedberg679d2b62015-10-16 10:07:52 +03005255 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5256 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005257 err = mgmt_cmd_complete(sk, hdev->id,
5258 MGMT_OP_REMOVE_DEVICE,
5259 MGMT_STATUS_INVALID_PARAMS,
5260 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005261 goto unlock;
5262 }
5263
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005264 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005265 list_del(&params->list);
5266 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005267 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005268
5269 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005270 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005271 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005272 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005273
Marcel Holtmann2faade52014-06-29 19:44:03 +02005274 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005275 err = mgmt_cmd_complete(sk, hdev->id,
5276 MGMT_OP_REMOVE_DEVICE,
5277 MGMT_STATUS_INVALID_PARAMS,
5278 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005279 goto unlock;
5280 }
5281
Johan Hedberg66593582014-07-09 12:59:14 +03005282 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5283 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5284 list_del(&b->list);
5285 kfree(b);
5286 }
5287
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005288 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005289
Johan Hedberg19de0822014-07-06 13:06:51 +03005290 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5291 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5292 continue;
5293 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005294 if (p->explicit_connect) {
5295 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5296 continue;
5297 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005298 list_del(&p->action);
5299 list_del(&p->list);
5300 kfree(p);
5301 }
5302
5303 BT_DBG("All LE connection parameters were removed");
5304
Johan Hedberg51d7a942015-11-11 08:11:18 +02005305 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005306 }
5307
Johan Hedberg66593582014-07-09 12:59:14 +03005308complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005309 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5310 MGMT_STATUS_SUCCESS, &cp->addr,
5311 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005312unlock:
5313 hci_dev_unlock(hdev);
5314 return err;
5315}
5316
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005317static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5318 u16 len)
5319{
5320 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005321 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5322 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005323 u16 param_count, expected_len;
5324 int i;
5325
5326 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005327 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5328 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005329
5330 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005331 if (param_count > max_param_count) {
5332 BT_ERR("load_conn_param: too big param_count value %u",
5333 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005334 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5335 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005336 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005337
5338 expected_len = sizeof(*cp) + param_count *
5339 sizeof(struct mgmt_conn_param);
5340 if (expected_len != len) {
5341 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5342 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005343 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5344 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005345 }
5346
5347 BT_DBG("%s param_count %u", hdev->name, param_count);
5348
5349 hci_dev_lock(hdev);
5350
5351 hci_conn_params_clear_disabled(hdev);
5352
5353 for (i = 0; i < param_count; i++) {
5354 struct mgmt_conn_param *param = &cp->params[i];
5355 struct hci_conn_params *hci_param;
5356 u16 min, max, latency, timeout;
5357 u8 addr_type;
5358
5359 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5360 param->addr.type);
5361
5362 if (param->addr.type == BDADDR_LE_PUBLIC) {
5363 addr_type = ADDR_LE_DEV_PUBLIC;
5364 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5365 addr_type = ADDR_LE_DEV_RANDOM;
5366 } else {
5367 BT_ERR("Ignoring invalid connection parameters");
5368 continue;
5369 }
5370
5371 min = le16_to_cpu(param->min_interval);
5372 max = le16_to_cpu(param->max_interval);
5373 latency = le16_to_cpu(param->latency);
5374 timeout = le16_to_cpu(param->timeout);
5375
5376 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5377 min, max, latency, timeout);
5378
5379 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5380 BT_ERR("Ignoring invalid connection parameters");
5381 continue;
5382 }
5383
5384 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5385 addr_type);
5386 if (!hci_param) {
5387 BT_ERR("Failed to add connection parameters");
5388 continue;
5389 }
5390
5391 hci_param->conn_min_interval = min;
5392 hci_param->conn_max_interval = max;
5393 hci_param->conn_latency = latency;
5394 hci_param->supervision_timeout = timeout;
5395 }
5396
5397 hci_dev_unlock(hdev);
5398
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005399 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5400 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005401}
5402
Marcel Holtmanndbece372014-07-04 18:11:55 +02005403static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5404 void *data, u16 len)
5405{
5406 struct mgmt_cp_set_external_config *cp = data;
5407 bool changed;
5408 int err;
5409
5410 BT_DBG("%s", hdev->name);
5411
5412 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005413 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5414 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005415
5416 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005417 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5418 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005419
5420 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005421 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5422 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005423
5424 hci_dev_lock(hdev);
5425
5426 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005427 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005428 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005429 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005430
5431 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5432 if (err < 0)
5433 goto unlock;
5434
5435 if (!changed)
5436 goto unlock;
5437
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005438 err = new_options(hdev, sk);
5439
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005440 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005441 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005442
Marcel Holtmann516018a2015-03-13 02:11:04 -07005443 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005444 hci_dev_set_flag(hdev, HCI_CONFIG);
5445 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005446
5447 queue_work(hdev->req_workqueue, &hdev->power_on);
5448 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005449 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005450 mgmt_index_added(hdev);
5451 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005452 }
5453
5454unlock:
5455 hci_dev_unlock(hdev);
5456 return err;
5457}
5458
Marcel Holtmann9713c172014-07-06 12:11:15 +02005459static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5460 void *data, u16 len)
5461{
5462 struct mgmt_cp_set_public_address *cp = data;
5463 bool changed;
5464 int err;
5465
5466 BT_DBG("%s", hdev->name);
5467
5468 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005469 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5470 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005471
5472 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005473 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5474 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005475
5476 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005477 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5478 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005479
5480 hci_dev_lock(hdev);
5481
5482 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5483 bacpy(&hdev->public_addr, &cp->bdaddr);
5484
5485 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5486 if (err < 0)
5487 goto unlock;
5488
5489 if (!changed)
5490 goto unlock;
5491
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005492 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005493 err = new_options(hdev, sk);
5494
5495 if (is_configured(hdev)) {
5496 mgmt_index_removed(hdev);
5497
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005498 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005499
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005500 hci_dev_set_flag(hdev, HCI_CONFIG);
5501 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005502
5503 queue_work(hdev->req_workqueue, &hdev->power_on);
5504 }
5505
5506unlock:
5507 hci_dev_unlock(hdev);
5508 return err;
5509}
5510
Marcel Holtmannbea41602015-03-14 22:43:17 -07005511static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5512 u8 data_len)
5513{
5514 eir[eir_len++] = sizeof(type) + data_len;
5515 eir[eir_len++] = type;
5516 memcpy(&eir[eir_len], data, data_len);
5517 eir_len += data_len;
5518
5519 return eir_len;
5520}
5521
Johan Hedberg40f66c02015-04-07 21:52:22 +03005522static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5523 u16 opcode, struct sk_buff *skb)
5524{
5525 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5526 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5527 u8 *h192, *r192, *h256, *r256;
5528 struct mgmt_pending_cmd *cmd;
5529 u16 eir_len;
5530 int err;
5531
5532 BT_DBG("%s status %u", hdev->name, status);
5533
5534 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5535 if (!cmd)
5536 return;
5537
5538 mgmt_cp = cmd->param;
5539
5540 if (status) {
5541 status = mgmt_status(status);
5542 eir_len = 0;
5543
5544 h192 = NULL;
5545 r192 = NULL;
5546 h256 = NULL;
5547 r256 = NULL;
5548 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5549 struct hci_rp_read_local_oob_data *rp;
5550
5551 if (skb->len != sizeof(*rp)) {
5552 status = MGMT_STATUS_FAILED;
5553 eir_len = 0;
5554 } else {
5555 status = MGMT_STATUS_SUCCESS;
5556 rp = (void *)skb->data;
5557
5558 eir_len = 5 + 18 + 18;
5559 h192 = rp->hash;
5560 r192 = rp->rand;
5561 h256 = NULL;
5562 r256 = NULL;
5563 }
5564 } else {
5565 struct hci_rp_read_local_oob_ext_data *rp;
5566
5567 if (skb->len != sizeof(*rp)) {
5568 status = MGMT_STATUS_FAILED;
5569 eir_len = 0;
5570 } else {
5571 status = MGMT_STATUS_SUCCESS;
5572 rp = (void *)skb->data;
5573
5574 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5575 eir_len = 5 + 18 + 18;
5576 h192 = NULL;
5577 r192 = NULL;
5578 } else {
5579 eir_len = 5 + 18 + 18 + 18 + 18;
5580 h192 = rp->hash192;
5581 r192 = rp->rand192;
5582 }
5583
5584 h256 = rp->hash256;
5585 r256 = rp->rand256;
5586 }
5587 }
5588
5589 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5590 if (!mgmt_rp)
5591 goto done;
5592
5593 if (status)
5594 goto send_rsp;
5595
5596 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5597 hdev->dev_class, 3);
5598
5599 if (h192 && r192) {
5600 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5601 EIR_SSP_HASH_C192, h192, 16);
5602 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5603 EIR_SSP_RAND_R192, r192, 16);
5604 }
5605
5606 if (h256 && r256) {
5607 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5608 EIR_SSP_HASH_C256, h256, 16);
5609 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5610 EIR_SSP_RAND_R256, r256, 16);
5611 }
5612
5613send_rsp:
5614 mgmt_rp->type = mgmt_cp->type;
5615 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5616
5617 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5618 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5619 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5620 if (err < 0 || status)
5621 goto done;
5622
5623 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5624
5625 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5626 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5627 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5628done:
5629 kfree(mgmt_rp);
5630 mgmt_pending_remove(cmd);
5631}
5632
5633static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5634 struct mgmt_cp_read_local_oob_ext_data *cp)
5635{
5636 struct mgmt_pending_cmd *cmd;
5637 struct hci_request req;
5638 int err;
5639
5640 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5641 cp, sizeof(*cp));
5642 if (!cmd)
5643 return -ENOMEM;
5644
5645 hci_req_init(&req, hdev);
5646
5647 if (bredr_sc_enabled(hdev))
5648 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5649 else
5650 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5651
5652 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5653 if (err < 0) {
5654 mgmt_pending_remove(cmd);
5655 return err;
5656 }
5657
5658 return 0;
5659}
5660
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005661static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5662 void *data, u16 data_len)
5663{
5664 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5665 struct mgmt_rp_read_local_oob_ext_data *rp;
5666 size_t rp_len;
5667 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005668 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005669 int err;
5670
5671 BT_DBG("%s", hdev->name);
5672
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005673 if (hdev_is_powered(hdev)) {
5674 switch (cp->type) {
5675 case BIT(BDADDR_BREDR):
5676 status = mgmt_bredr_support(hdev);
5677 if (status)
5678 eir_len = 0;
5679 else
5680 eir_len = 5;
5681 break;
5682 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5683 status = mgmt_le_support(hdev);
5684 if (status)
5685 eir_len = 0;
5686 else
5687 eir_len = 9 + 3 + 18 + 18 + 3;
5688 break;
5689 default:
5690 status = MGMT_STATUS_INVALID_PARAMS;
5691 eir_len = 0;
5692 break;
5693 }
5694 } else {
5695 status = MGMT_STATUS_NOT_POWERED;
5696 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005697 }
5698
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005699 rp_len = sizeof(*rp) + eir_len;
5700 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005701 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005702 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005703
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005704 if (status)
5705 goto complete;
5706
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005707 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005708
5709 eir_len = 0;
5710 switch (cp->type) {
5711 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005712 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5713 err = read_local_ssp_oob_req(hdev, sk, cp);
5714 hci_dev_unlock(hdev);
5715 if (!err)
5716 goto done;
5717
5718 status = MGMT_STATUS_FAILED;
5719 goto complete;
5720 } else {
5721 eir_len = eir_append_data(rp->eir, eir_len,
5722 EIR_CLASS_OF_DEV,
5723 hdev->dev_class, 3);
5724 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005725 break;
5726 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005727 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5728 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005729 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005730 status = MGMT_STATUS_FAILED;
5731 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005732 }
5733
Marcel Holtmanne2135682015-04-02 12:00:58 -07005734 /* This should return the active RPA, but since the RPA
5735 * is only programmed on demand, it is really hard to fill
5736 * this in at the moment. For now disallow retrieving
5737 * local out-of-band data when privacy is in use.
5738 *
5739 * Returning the identity address will not help here since
5740 * pairing happens before the identity resolving key is
5741 * known and thus the connection establishment happens
5742 * based on the RPA and not the identity address.
5743 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005744 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005745 hci_dev_unlock(hdev);
5746 status = MGMT_STATUS_REJECTED;
5747 goto complete;
5748 }
5749
5750 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5751 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5752 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5753 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005754 memcpy(addr, &hdev->static_addr, 6);
5755 addr[6] = 0x01;
5756 } else {
5757 memcpy(addr, &hdev->bdaddr, 6);
5758 addr[6] = 0x00;
5759 }
5760
5761 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5762 addr, sizeof(addr));
5763
5764 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5765 role = 0x02;
5766 else
5767 role = 0x01;
5768
5769 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5770 &role, sizeof(role));
5771
Marcel Holtmann5082a592015-03-16 12:39:00 -07005772 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5773 eir_len = eir_append_data(rp->eir, eir_len,
5774 EIR_LE_SC_CONFIRM,
5775 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005776
Marcel Holtmann5082a592015-03-16 12:39:00 -07005777 eir_len = eir_append_data(rp->eir, eir_len,
5778 EIR_LE_SC_RANDOM,
5779 rand, sizeof(rand));
5780 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005781
Johan Hedbergf2252572015-11-18 12:49:20 +02005782 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005783
5784 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5785 flags |= LE_AD_NO_BREDR;
5786
5787 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5788 &flags, sizeof(flags));
5789 break;
5790 }
5791
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005792 hci_dev_unlock(hdev);
5793
Marcel Holtmann72000df2015-03-16 16:11:21 -07005794 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5795
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005796 status = MGMT_STATUS_SUCCESS;
5797
5798complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005799 rp->type = cp->type;
5800 rp->eir_len = cpu_to_le16(eir_len);
5801
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005802 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005803 status, rp, sizeof(*rp) + eir_len);
5804 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005805 goto done;
5806
5807 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5808 rp, sizeof(*rp) + eir_len,
5809 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005810
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005811done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005812 kfree(rp);
5813
5814 return err;
5815}
5816
Arman Uguray089fa8c2015-03-25 18:53:45 -07005817static u32 get_supported_adv_flags(struct hci_dev *hdev)
5818{
5819 u32 flags = 0;
5820
5821 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5822 flags |= MGMT_ADV_FLAG_DISCOV;
5823 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5824 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
5825
5826 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5827 flags |= MGMT_ADV_FLAG_TX_POWER;
5828
5829 return flags;
5830}
5831
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005832static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5833 void *data, u16 data_len)
5834{
5835 struct mgmt_rp_read_adv_features *rp;
5836 size_t rp_len;
Florian Grandel286e0c82015-06-18 03:16:38 +02005837 int err, i;
Arman Uguray24b4f382015-03-23 15:57:12 -07005838 bool instance;
Florian Grandel286e0c82015-06-18 03:16:38 +02005839 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005840 u32 supported_flags;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005841
5842 BT_DBG("%s", hdev->name);
5843
Arman Uguray089fa8c2015-03-25 18:53:45 -07005844 if (!lmp_le_capable(hdev))
5845 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5846 MGMT_STATUS_REJECTED);
5847
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005848 hci_dev_lock(hdev);
5849
5850 rp_len = sizeof(*rp);
Arman Uguray24b4f382015-03-23 15:57:12 -07005851
Arman Uguray24b4f382015-03-23 15:57:12 -07005852 instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
5853 if (instance)
Florian Grandel286e0c82015-06-18 03:16:38 +02005854 rp_len += hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005855
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005856 rp = kmalloc(rp_len, GFP_ATOMIC);
5857 if (!rp) {
5858 hci_dev_unlock(hdev);
5859 return -ENOMEM;
5860 }
5861
Arman Uguray089fa8c2015-03-25 18:53:45 -07005862 supported_flags = get_supported_adv_flags(hdev);
5863
5864 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005865 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5866 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005867 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Arman Uguray24b4f382015-03-23 15:57:12 -07005868
Arman Uguray24b4f382015-03-23 15:57:12 -07005869 if (instance) {
Florian Grandel286e0c82015-06-18 03:16:38 +02005870 i = 0;
5871 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5872 if (i >= hdev->adv_instance_cnt)
5873 break;
5874
5875 rp->instance[i] = adv_instance->instance;
5876 i++;
5877 }
5878 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005879 } else {
5880 rp->num_instances = 0;
5881 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005882
5883 hci_dev_unlock(hdev);
5884
5885 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5886 MGMT_STATUS_SUCCESS, rp, rp_len);
5887
5888 kfree(rp);
5889
5890 return err;
5891}
5892
Arman Uguray4117ed72015-03-23 15:57:14 -07005893static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005894 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005895{
Arman Uguray4117ed72015-03-23 15:57:14 -07005896 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005897 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005898 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005899 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005900
Marcel Holtmann31a32482015-11-19 16:16:42 +01005901 if (is_adv_data) {
5902 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5903 MGMT_ADV_FLAG_LIMITED_DISCOV |
5904 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5905 flags_managed = true;
5906 max_len -= 3;
5907 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005908
Marcel Holtmann31a32482015-11-19 16:16:42 +01005909 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5910 tx_power_managed = true;
5911 max_len -= 3;
5912 }
Arman Uguray5507e352015-03-25 18:53:44 -07005913 }
5914
Arman Uguray4117ed72015-03-23 15:57:14 -07005915 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005916 return false;
5917
Arman Uguray4117ed72015-03-23 15:57:14 -07005918 /* Make sure that the data is correctly formatted. */
5919 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
5920 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07005921
Arman Ugurayb44133f2015-03-25 18:53:41 -07005922 if (flags_managed && data[i + 1] == EIR_FLAGS)
5923 return false;
5924
Arman Uguray5507e352015-03-25 18:53:44 -07005925 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
5926 return false;
5927
Arman Uguray24b4f382015-03-23 15:57:12 -07005928 /* If the current field length would exceed the total data
5929 * length, then it's invalid.
5930 */
Arman Uguray4117ed72015-03-23 15:57:14 -07005931 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005932 return false;
5933 }
5934
5935 return true;
5936}
5937
Arman Uguray24b4f382015-03-23 15:57:12 -07005938static void add_advertising_complete(struct hci_dev *hdev, u8 status,
5939 u16 opcode)
5940{
5941 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005942 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07005943 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005944 struct adv_info *adv_instance, *n;
5945 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005946
5947 BT_DBG("status %d", status);
5948
5949 hci_dev_lock(hdev);
5950
5951 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
5952
Florian Grandelfffd38b2015-06-18 03:16:47 +02005953 if (status)
Arman Uguray24b4f382015-03-23 15:57:12 -07005954 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005955
5956 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
5957 if (!adv_instance->pending)
5958 continue;
5959
5960 if (!status) {
5961 adv_instance->pending = false;
5962 continue;
5963 }
5964
5965 instance = adv_instance->instance;
5966
5967 if (hdev->cur_adv_instance == instance)
5968 cancel_adv_timeout(hdev);
5969
5970 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02005971 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07005972 }
5973
5974 if (!cmd)
5975 goto unlock;
5976
Florian Grandelfffd38b2015-06-18 03:16:47 +02005977 cp = cmd->param;
5978 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005979
5980 if (status)
5981 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5982 mgmt_status(status));
5983 else
5984 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
5985 mgmt_status(status), &rp, sizeof(rp));
5986
5987 mgmt_pending_remove(cmd);
5988
5989unlock:
5990 hci_dev_unlock(hdev);
5991}
5992
5993static int add_advertising(struct sock *sk, struct hci_dev *hdev,
5994 void *data, u16 data_len)
5995{
5996 struct mgmt_cp_add_advertising *cp = data;
5997 struct mgmt_rp_add_advertising rp;
5998 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005999 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006000 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006001 u16 timeout, duration;
6002 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6003 u8 schedule_instance = 0;
6004 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006005 int err;
6006 struct mgmt_pending_cmd *cmd;
6007 struct hci_request req;
6008
6009 BT_DBG("%s", hdev->name);
6010
6011 status = mgmt_le_support(hdev);
6012 if (status)
6013 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6014 status);
6015
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006016 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6017 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6018 MGMT_STATUS_INVALID_PARAMS);
6019
Arman Uguray24b4f382015-03-23 15:57:12 -07006020 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006021 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006022 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006023
Florian Grandelfffd38b2015-06-18 03:16:47 +02006024 /* The current implementation only supports a subset of the specified
6025 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006026 */
6027 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006028 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006029 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6030 MGMT_STATUS_INVALID_PARAMS);
6031
6032 hci_dev_lock(hdev);
6033
Arman Uguray912098a2015-03-23 15:57:15 -07006034 if (timeout && !hdev_is_powered(hdev)) {
6035 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6036 MGMT_STATUS_REJECTED);
6037 goto unlock;
6038 }
6039
Arman Uguray24b4f382015-03-23 15:57:12 -07006040 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006041 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006042 pending_find(MGMT_OP_SET_LE, hdev)) {
6043 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6044 MGMT_STATUS_BUSY);
6045 goto unlock;
6046 }
6047
Arman Ugurayb44133f2015-03-25 18:53:41 -07006048 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006049 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006050 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006051 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6052 MGMT_STATUS_INVALID_PARAMS);
6053 goto unlock;
6054 }
6055
Florian Grandelfffd38b2015-06-18 03:16:47 +02006056 err = hci_add_adv_instance(hdev, cp->instance, flags,
6057 cp->adv_data_len, cp->data,
6058 cp->scan_rsp_len,
6059 cp->data + cp->adv_data_len,
6060 timeout, duration);
6061 if (err < 0) {
6062 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6063 MGMT_STATUS_FAILED);
6064 goto unlock;
6065 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006066
Florian Grandelfffd38b2015-06-18 03:16:47 +02006067 /* Only trigger an advertising added event if a new instance was
6068 * actually added.
6069 */
6070 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006071 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006072
Florian Grandelfffd38b2015-06-18 03:16:47 +02006073 hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
Arman Uguray24b4f382015-03-23 15:57:12 -07006074
Florian Grandelfffd38b2015-06-18 03:16:47 +02006075 if (hdev->cur_adv_instance == cp->instance) {
6076 /* If the currently advertised instance is being changed then
6077 * cancel the current advertising and schedule the next
6078 * instance. If there is only one instance then the overridden
6079 * advertising data will be visible right away.
6080 */
6081 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006082
Florian Grandelfffd38b2015-06-18 03:16:47 +02006083 next_instance = hci_get_next_instance(hdev, cp->instance);
6084 if (next_instance)
6085 schedule_instance = next_instance->instance;
6086 } else if (!hdev->adv_instance_timeout) {
6087 /* Immediately advertise the new instance if no other
6088 * instance is currently being advertised.
6089 */
6090 schedule_instance = cp->instance;
6091 }
Arman Uguray912098a2015-03-23 15:57:15 -07006092
Florian Grandelfffd38b2015-06-18 03:16:47 +02006093 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6094 * there is no instance to be advertised then we have no HCI
6095 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006096 */
6097 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006098 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6099 !schedule_instance) {
6100 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006101 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6102 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6103 goto unlock;
6104 }
6105
6106 /* We're good to go, update advertising data, parameters, and start
6107 * advertising.
6108 */
6109 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6110 data_len);
6111 if (!cmd) {
6112 err = -ENOMEM;
6113 goto unlock;
6114 }
6115
6116 hci_req_init(&req, hdev);
6117
Johan Hedbergf2252572015-11-18 12:49:20 +02006118 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006119
Florian Grandelfffd38b2015-06-18 03:16:47 +02006120 if (!err)
6121 err = hci_req_run(&req, add_advertising_complete);
6122
Arman Uguray24b4f382015-03-23 15:57:12 -07006123 if (err < 0)
6124 mgmt_pending_remove(cmd);
6125
6126unlock:
6127 hci_dev_unlock(hdev);
6128
6129 return err;
6130}
6131
Arman Ugurayda9293352015-03-23 15:57:13 -07006132static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6133 u16 opcode)
6134{
6135 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006136 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006137 struct mgmt_rp_remove_advertising rp;
6138
6139 BT_DBG("status %d", status);
6140
6141 hci_dev_lock(hdev);
6142
6143 /* A failure status here only means that we failed to disable
6144 * advertising. Otherwise, the advertising instance has been removed,
6145 * so report success.
6146 */
6147 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6148 if (!cmd)
6149 goto unlock;
6150
Florian Grandel01948332015-06-18 03:16:48 +02006151 cp = cmd->param;
6152 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006153
6154 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6155 &rp, sizeof(rp));
6156 mgmt_pending_remove(cmd);
6157
6158unlock:
6159 hci_dev_unlock(hdev);
6160}
6161
6162static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6163 void *data, u16 data_len)
6164{
6165 struct mgmt_cp_remove_advertising *cp = data;
6166 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006167 struct mgmt_pending_cmd *cmd;
6168 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006169 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006170
6171 BT_DBG("%s", hdev->name);
6172
Arman Ugurayda9293352015-03-23 15:57:13 -07006173 hci_dev_lock(hdev);
6174
Johan Hedberg952497b2015-06-18 21:05:31 +03006175 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006176 err = mgmt_cmd_status(sk, hdev->id,
6177 MGMT_OP_REMOVE_ADVERTISING,
6178 MGMT_STATUS_INVALID_PARAMS);
6179 goto unlock;
6180 }
6181
Arman Ugurayda9293352015-03-23 15:57:13 -07006182 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6183 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6184 pending_find(MGMT_OP_SET_LE, hdev)) {
6185 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6186 MGMT_STATUS_BUSY);
6187 goto unlock;
6188 }
6189
6190 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
6191 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6192 MGMT_STATUS_INVALID_PARAMS);
6193 goto unlock;
6194 }
6195
Florian Grandel01948332015-06-18 03:16:48 +02006196 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006197
Johan Hedbergf2252572015-11-18 12:49:20 +02006198 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006199
Florian Grandel01948332015-06-18 03:16:48 +02006200 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006201 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006202
Florian Grandel01948332015-06-18 03:16:48 +02006203 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6204 * flag is set or the device isn't powered then we have no HCI
6205 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006206 */
Florian Grandel01948332015-06-18 03:16:48 +02006207 if (skb_queue_empty(&req.cmd_q) ||
6208 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006209 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006210 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006211 err = mgmt_cmd_complete(sk, hdev->id,
6212 MGMT_OP_REMOVE_ADVERTISING,
6213 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6214 goto unlock;
6215 }
6216
6217 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6218 data_len);
6219 if (!cmd) {
6220 err = -ENOMEM;
6221 goto unlock;
6222 }
6223
Arman Ugurayda9293352015-03-23 15:57:13 -07006224 err = hci_req_run(&req, remove_advertising_complete);
6225 if (err < 0)
6226 mgmt_pending_remove(cmd);
6227
6228unlock:
6229 hci_dev_unlock(hdev);
6230
6231 return err;
6232}
6233
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006234static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6235{
6236 u8 max_len = HCI_MAX_AD_LENGTH;
6237
6238 if (is_adv_data) {
6239 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6240 MGMT_ADV_FLAG_LIMITED_DISCOV |
6241 MGMT_ADV_FLAG_MANAGED_FLAGS))
6242 max_len -= 3;
6243
6244 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6245 max_len -= 3;
6246 }
6247
6248 return max_len;
6249}
6250
6251static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6252 void *data, u16 data_len)
6253{
6254 struct mgmt_cp_get_adv_size_info *cp = data;
6255 struct mgmt_rp_get_adv_size_info rp;
6256 u32 flags, supported_flags;
6257 int err;
6258
6259 BT_DBG("%s", hdev->name);
6260
6261 if (!lmp_le_capable(hdev))
6262 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6263 MGMT_STATUS_REJECTED);
6264
6265 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6266 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6267 MGMT_STATUS_INVALID_PARAMS);
6268
6269 flags = __le32_to_cpu(cp->flags);
6270
6271 /* The current implementation only supports a subset of the specified
6272 * flags.
6273 */
6274 supported_flags = get_supported_adv_flags(hdev);
6275 if (flags & ~supported_flags)
6276 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6277 MGMT_STATUS_INVALID_PARAMS);
6278
6279 rp.instance = cp->instance;
6280 rp.flags = cp->flags;
6281 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6282 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6283
6284 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6285 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6286
6287 return err;
6288}
6289
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006290static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006291 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006292 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006293 HCI_MGMT_NO_HDEV |
6294 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006295 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006296 HCI_MGMT_NO_HDEV |
6297 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006298 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006299 HCI_MGMT_NO_HDEV |
6300 HCI_MGMT_UNTRUSTED },
6301 { read_controller_info, MGMT_READ_INFO_SIZE,
6302 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006303 { set_powered, MGMT_SETTING_SIZE },
6304 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6305 { set_connectable, MGMT_SETTING_SIZE },
6306 { set_fast_connectable, MGMT_SETTING_SIZE },
6307 { set_bondable, MGMT_SETTING_SIZE },
6308 { set_link_security, MGMT_SETTING_SIZE },
6309 { set_ssp, MGMT_SETTING_SIZE },
6310 { set_hs, MGMT_SETTING_SIZE },
6311 { set_le, MGMT_SETTING_SIZE },
6312 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6313 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6314 { add_uuid, MGMT_ADD_UUID_SIZE },
6315 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006316 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6317 HCI_MGMT_VAR_LEN },
6318 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6319 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006320 { disconnect, MGMT_DISCONNECT_SIZE },
6321 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6322 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6323 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6324 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6325 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6326 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6327 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6328 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6329 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6330 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6331 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006332 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6333 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6334 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006335 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6336 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6337 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6338 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6339 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6340 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6341 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6342 { set_advertising, MGMT_SETTING_SIZE },
6343 { set_bredr, MGMT_SETTING_SIZE },
6344 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6345 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6346 { set_secure_conn, MGMT_SETTING_SIZE },
6347 { set_debug_keys, MGMT_SETTING_SIZE },
6348 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006349 { load_irks, MGMT_LOAD_IRKS_SIZE,
6350 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006351 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6352 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6353 { add_device, MGMT_ADD_DEVICE_SIZE },
6354 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006355 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6356 HCI_MGMT_VAR_LEN },
6357 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006358 HCI_MGMT_NO_HDEV |
6359 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006360 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006361 HCI_MGMT_UNCONFIGURED |
6362 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006363 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6364 HCI_MGMT_UNCONFIGURED },
6365 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6366 HCI_MGMT_UNCONFIGURED },
6367 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6368 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006369 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006370 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006371 HCI_MGMT_NO_HDEV |
6372 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006373 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006374 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6375 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006376 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006377 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006378};
6379
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006380void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006381{
Marcel Holtmannced85542015-03-14 19:27:56 -07006382 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006383
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006384 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6385 return;
6386
Marcel Holtmannf9207332015-03-14 19:27:55 -07006387 switch (hdev->dev_type) {
6388 case HCI_BREDR:
6389 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6390 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6391 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006392 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006393 } else {
6394 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6395 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006396 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006397 }
6398 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006399 case HCI_AMP:
6400 ev.type = 0x02;
6401 break;
6402 default:
6403 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006404 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006405
6406 ev.bus = hdev->bus;
6407
6408 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6409 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006410}
6411
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006412void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006413{
Marcel Holtmannced85542015-03-14 19:27:56 -07006414 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006415 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006416
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006417 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6418 return;
6419
Marcel Holtmannf9207332015-03-14 19:27:55 -07006420 switch (hdev->dev_type) {
6421 case HCI_BREDR:
6422 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006423
Marcel Holtmannf9207332015-03-14 19:27:55 -07006424 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6425 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6426 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006427 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006428 } else {
6429 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6430 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006431 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006432 }
6433 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006434 case HCI_AMP:
6435 ev.type = 0x02;
6436 break;
6437 default:
6438 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006439 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006440
6441 ev.bus = hdev->bus;
6442
6443 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6444 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006445}
6446
Andre Guedes6046dc32014-02-26 20:21:51 -03006447/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006448static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006449{
6450 struct hci_conn_params *p;
6451
6452 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006453 /* Needed for AUTO_OFF case where might not "really"
6454 * have been powered off.
6455 */
6456 list_del_init(&p->action);
6457
6458 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006459 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006460 case HCI_AUTO_CONN_ALWAYS:
6461 list_add(&p->action, &hdev->pend_le_conns);
6462 break;
6463 case HCI_AUTO_CONN_REPORT:
6464 list_add(&p->action, &hdev->pend_le_reports);
6465 break;
6466 default:
6467 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006468 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006469 }
6470}
6471
Marcel Holtmann1904a852015-01-11 13:50:44 -08006472static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006473{
6474 struct cmd_lookup match = { NULL, hdev };
6475
6476 BT_DBG("status 0x%02x", status);
6477
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006478 if (!status) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006479 restart_le_actions(hdev);
6480 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006481 }
6482
Johan Hedberg229ab392013-03-15 17:06:53 -05006483 hci_dev_lock(hdev);
6484
6485 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6486
6487 new_settings(hdev, match.sk);
6488
6489 hci_dev_unlock(hdev);
6490
6491 if (match.sk)
6492 sock_put(match.sk);
6493}
6494
Johan Hedberg70da6242013-03-15 17:06:51 -05006495static int powered_update_hci(struct hci_dev *hdev)
6496{
Johan Hedberg890ea892013-03-15 17:06:52 -05006497 struct hci_request req;
Florian Grandel320b3bf2015-06-18 03:16:49 +02006498 struct adv_info *adv_instance;
Johan Hedberg70da6242013-03-15 17:06:51 -05006499 u8 link_sec;
6500
Johan Hedberg890ea892013-03-15 17:06:52 -05006501 hci_req_init(&req, hdev);
6502
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006503 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006504 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006505 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006506
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006507 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006508
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006509 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6510 u8 support = 0x01;
6511
6512 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6513 sizeof(support), &support);
6514 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006515 }
6516
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006517 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006518 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006519 struct hci_cp_write_le_host_supported cp;
6520
Marcel Holtmann32226e42014-07-24 20:04:16 +02006521 cp.le = 0x01;
6522 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006523
6524 /* Check first if we already have the right
6525 * host state (host features set)
6526 */
6527 if (cp.le != lmp_host_le_capable(hdev) ||
6528 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006529 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6530 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006531 }
6532
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006533 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006534 /* Make sure the controller has a good default for
6535 * advertising data. This also applies to the case
6536 * where BR/EDR was toggled during the AUTO_OFF phase.
6537 */
Florian Grandel320b3bf2015-06-18 03:16:49 +02006538 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
6539 (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6540 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
Johan Hedbergf2252572015-11-18 12:49:20 +02006541 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
6542 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006543 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006544
Florian Grandel320b3bf2015-06-18 03:16:49 +02006545 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6546 hdev->cur_adv_instance == 0x00 &&
6547 !list_empty(&hdev->adv_instances)) {
6548 adv_instance = list_first_entry(&hdev->adv_instances,
6549 struct adv_info, list);
6550 hdev->cur_adv_instance = adv_instance->instance;
6551 }
6552
6553 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergf2252572015-11-18 12:49:20 +02006554 __hci_req_enable_advertising(&req);
Florian Grandel320b3bf2015-06-18 03:16:49 +02006555 else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6556 hdev->cur_adv_instance)
Johan Hedbergf2252572015-11-18 12:49:20 +02006557 __hci_req_schedule_adv_instance(&req,
6558 hdev->cur_adv_instance,
6559 true);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006560 }
6561
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006562 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006563 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006564 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6565 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006566
6567 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006568 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006569 write_fast_connectable(&req, true);
6570 else
6571 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006572 __hci_req_update_scan(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02006573 __hci_req_update_class(&req);
Johan Hedberg00cf5042015-11-25 16:15:41 +02006574 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02006575 __hci_req_update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006576 }
6577
Johan Hedberg229ab392013-03-15 17:06:53 -05006578 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006579}
6580
Johan Hedberg744cf192011-11-08 20:40:14 +02006581int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006582{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006583 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006584 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006585 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006586
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006587 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006588 return 0;
6589
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006590 if (powered) {
Andrzej Kaczmareke59a5542015-11-22 21:42:21 +01006591 /* Register the available SMP channels (BR/EDR and LE) only
6592 * when successfully powering on the controller. This late
6593 * registration is required so that LE SMP can clearly
6594 * decide if the public address or static address is used.
6595 */
6596 smp_register(hdev);
6597
Johan Hedberg229ab392013-03-15 17:06:53 -05006598 if (powered_update_hci(hdev) == 0)
6599 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006600
Johan Hedberg229ab392013-03-15 17:06:53 -05006601 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6602 &match);
6603 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006604 }
6605
Johan Hedberg229ab392013-03-15 17:06:53 -05006606 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006607
6608 /* If the power off is because of hdev unregistration let
6609 * use the appropriate INVALID_INDEX status. Otherwise use
6610 * NOT_POWERED. We cover both scenarios here since later in
6611 * mgmt_index_removed() any hci_conn callbacks will have already
6612 * been triggered, potentially causing misleading DISCONNECTED
6613 * status responses.
6614 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006615 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006616 status = MGMT_STATUS_INVALID_INDEX;
6617 else
6618 status = MGMT_STATUS_NOT_POWERED;
6619
6620 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006621
6622 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006623 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6624 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006625
6626new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006627 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006628
6629 if (match.sk)
6630 sock_put(match.sk);
6631
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006632 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006633}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006634
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006635void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006636{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006637 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006638 u8 status;
6639
Johan Hedberg333ae952015-03-17 13:48:47 +02006640 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006641 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006642 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006643
6644 if (err == -ERFKILL)
6645 status = MGMT_STATUS_RFKILLED;
6646 else
6647 status = MGMT_STATUS_FAILED;
6648
Johan Hedberga69e8372015-03-06 21:08:53 +02006649 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006650
6651 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006652}
6653
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006654void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6655 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006656{
Johan Hedberg86742e12011-11-07 23:13:38 +02006657 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006658
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006659 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006660
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006661 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006662 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006663 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006664 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006665 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006666 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006667
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006668 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006669}
Johan Hedbergf7520542011-01-20 12:34:39 +02006670
Johan Hedbergd7b25452014-05-23 13:19:53 +03006671static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6672{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006673 switch (ltk->type) {
6674 case SMP_LTK:
6675 case SMP_LTK_SLAVE:
6676 if (ltk->authenticated)
6677 return MGMT_LTK_AUTHENTICATED;
6678 return MGMT_LTK_UNAUTHENTICATED;
6679 case SMP_LTK_P256:
6680 if (ltk->authenticated)
6681 return MGMT_LTK_P256_AUTH;
6682 return MGMT_LTK_P256_UNAUTH;
6683 case SMP_LTK_P256_DEBUG:
6684 return MGMT_LTK_P256_DEBUG;
6685 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006686
6687 return MGMT_LTK_UNAUTHENTICATED;
6688}
6689
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006690void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006691{
6692 struct mgmt_ev_new_long_term_key ev;
6693
6694 memset(&ev, 0, sizeof(ev));
6695
Marcel Holtmann5192d302014-02-19 17:11:58 -08006696 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006697 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006698 * to store long term keys. Their addresses will change the
6699 * next time around.
6700 *
6701 * Only when a remote device provides an identity address
6702 * make sure the long term key is stored. If the remote
6703 * identity is known, the long term keys are internally
6704 * mapped to the identity address. So allow static random
6705 * and public addresses here.
6706 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006707 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6708 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6709 ev.store_hint = 0x00;
6710 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006711 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006712
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006713 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006714 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006715 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006716 ev.key.enc_size = key->enc_size;
6717 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006718 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006719
Johan Hedberg2ceba532014-06-16 19:25:16 +03006720 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006721 ev.key.master = 1;
6722
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006723 /* Make sure we copy only the significant bytes based on the
6724 * encryption key size, and set the rest of the value to zeroes.
6725 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006726 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006727 memset(ev.key.val + key->enc_size, 0,
6728 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006729
Marcel Holtmann083368f2013-10-15 14:26:29 -07006730 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006731}
6732
Johan Hedbergcad20c22015-10-12 13:36:19 +02006733void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006734{
6735 struct mgmt_ev_new_irk ev;
6736
6737 memset(&ev, 0, sizeof(ev));
6738
Johan Hedbergcad20c22015-10-12 13:36:19 +02006739 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006740
Johan Hedberg95fbac82014-02-19 15:18:31 +02006741 bacpy(&ev.rpa, &irk->rpa);
6742 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6743 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6744 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6745
6746 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6747}
6748
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006749void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6750 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006751{
6752 struct mgmt_ev_new_csrk ev;
6753
6754 memset(&ev, 0, sizeof(ev));
6755
6756 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006757 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006758 * to store signature resolving keys. Their addresses will change
6759 * the next time around.
6760 *
6761 * Only when a remote device provides an identity address
6762 * make sure the signature resolving key is stored. So allow
6763 * static random and public addresses here.
6764 */
6765 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6766 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6767 ev.store_hint = 0x00;
6768 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006769 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006770
6771 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6772 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006773 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006774 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6775
6776 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6777}
6778
Andre Guedesffb5a8272014-07-01 18:10:11 -03006779void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006780 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6781 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006782{
6783 struct mgmt_ev_new_conn_param ev;
6784
Johan Hedbergc103aea2014-07-02 17:37:34 +03006785 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6786 return;
6787
Andre Guedesffb5a8272014-07-01 18:10:11 -03006788 memset(&ev, 0, sizeof(ev));
6789 bacpy(&ev.addr.bdaddr, bdaddr);
6790 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006791 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006792 ev.min_interval = cpu_to_le16(min_interval);
6793 ev.max_interval = cpu_to_le16(max_interval);
6794 ev.latency = cpu_to_le16(latency);
6795 ev.timeout = cpu_to_le16(timeout);
6796
6797 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6798}
6799
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006800void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6801 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006802{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006803 char buf[512];
6804 struct mgmt_ev_device_connected *ev = (void *) buf;
6805 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006806
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006807 bacpy(&ev->addr.bdaddr, &conn->dst);
6808 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006809
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006810 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006811
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006812 /* We must ensure that the EIR Data fields are ordered and
6813 * unique. Keep it simple for now and avoid the problem by not
6814 * adding any BR/EDR data to the LE adv.
6815 */
6816 if (conn->le_adv_data_len > 0) {
6817 memcpy(&ev->eir[eir_len],
6818 conn->le_adv_data, conn->le_adv_data_len);
6819 eir_len = conn->le_adv_data_len;
6820 } else {
6821 if (name_len > 0)
6822 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6823 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006824
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006825 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006826 eir_len = eir_append_data(ev->eir, eir_len,
6827 EIR_CLASS_OF_DEV,
6828 conn->dev_class, 3);
6829 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006830
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006831 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006832
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006833 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6834 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006835}
6836
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006837static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006838{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006839 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006840
Johan Hedbergf5818c22014-12-05 13:36:02 +02006841 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006842
6843 *sk = cmd->sk;
6844 sock_hold(*sk);
6845
Johan Hedberga664b5b2011-02-19 12:06:02 -03006846 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006847}
6848
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006849static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006850{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006851 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006852 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006853
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006854 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6855
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006856 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006857 mgmt_pending_remove(cmd);
6858}
6859
Johan Hedberg84c61d92014-08-01 11:13:30 +03006860bool mgmt_powering_down(struct hci_dev *hdev)
6861{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006862 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006863 struct mgmt_mode *cp;
6864
Johan Hedberg333ae952015-03-17 13:48:47 +02006865 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006866 if (!cmd)
6867 return false;
6868
6869 cp = cmd->param;
6870 if (!cp->val)
6871 return true;
6872
6873 return false;
6874}
6875
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006876void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006877 u8 link_type, u8 addr_type, u8 reason,
6878 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006879{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006880 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006881 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006882
Johan Hedberg84c61d92014-08-01 11:13:30 +03006883 /* The connection is still in hci_conn_hash so test for 1
6884 * instead of 0 to know if this is the last one.
6885 */
6886 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6887 cancel_delayed_work(&hdev->power_off);
6888 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006889 }
6890
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006891 if (!mgmt_connected)
6892 return;
6893
Andre Guedes57eb7762013-10-30 19:01:41 -03006894 if (link_type != ACL_LINK && link_type != LE_LINK)
6895 return;
6896
Johan Hedberg744cf192011-11-08 20:40:14 +02006897 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006898
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006899 bacpy(&ev.addr.bdaddr, bdaddr);
6900 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6901 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006902
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006903 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006904
6905 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006906 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006907
Johan Hedberg124f6e32012-02-09 13:50:12 +02006908 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006909 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006910}
6911
Marcel Holtmann78929242013-10-06 23:55:47 -07006912void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6913 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006914{
Andre Guedes3655bba2013-10-30 19:01:40 -03006915 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6916 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006917 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006918
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006919 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6920 hdev);
6921
Johan Hedberg333ae952015-03-17 13:48:47 +02006922 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006923 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006924 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006925
Andre Guedes3655bba2013-10-30 19:01:40 -03006926 cp = cmd->param;
6927
6928 if (bacmp(bdaddr, &cp->addr.bdaddr))
6929 return;
6930
6931 if (cp->addr.type != bdaddr_type)
6932 return;
6933
Johan Hedbergf5818c22014-12-05 13:36:02 +02006934 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006935 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006936}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006937
Marcel Holtmann445608d2013-10-06 23:55:48 -07006938void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6939 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006940{
6941 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006942
Johan Hedberg84c61d92014-08-01 11:13:30 +03006943 /* The connection is still in hci_conn_hash so test for 1
6944 * instead of 0 to know if this is the last one.
6945 */
6946 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6947 cancel_delayed_work(&hdev->power_off);
6948 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006949 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006950
Johan Hedberg4c659c32011-11-07 23:13:39 +02006951 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006952 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006953 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006954
Marcel Holtmann445608d2013-10-06 23:55:48 -07006955 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006956}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006957
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006958void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006959{
6960 struct mgmt_ev_pin_code_request ev;
6961
Johan Hedbergd8457692012-02-17 14:24:57 +02006962 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006963 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006964 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006965
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006966 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006967}
6968
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006969void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6970 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006971{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006972 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006973
Johan Hedberg333ae952015-03-17 13:48:47 +02006974 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006975 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006976 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006977
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006978 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006979 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006980}
6981
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006982void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6983 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006984{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006985 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006986
Johan Hedberg333ae952015-03-17 13:48:47 +02006987 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006988 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006989 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006990
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006991 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006992 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006993}
Johan Hedberga5c29682011-02-19 12:05:57 -03006994
Johan Hedberg744cf192011-11-08 20:40:14 +02006995int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006996 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006997 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006998{
6999 struct mgmt_ev_user_confirm_request ev;
7000
Johan Hedberg744cf192011-11-08 20:40:14 +02007001 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007002
Johan Hedberg272d90d2012-02-09 15:26:12 +02007003 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007004 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007005 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007006 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007007
Johan Hedberg744cf192011-11-08 20:40:14 +02007008 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007009 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007010}
7011
Johan Hedberg272d90d2012-02-09 15:26:12 +02007012int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007013 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007014{
7015 struct mgmt_ev_user_passkey_request ev;
7016
7017 BT_DBG("%s", hdev->name);
7018
Johan Hedberg272d90d2012-02-09 15:26:12 +02007019 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007020 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007021
7022 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007023 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007024}
7025
Brian Gix0df4c182011-11-16 13:53:13 -08007026static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007027 u8 link_type, u8 addr_type, u8 status,
7028 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007029{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007030 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007031
Johan Hedberg333ae952015-03-17 13:48:47 +02007032 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007033 if (!cmd)
7034 return -ENOENT;
7035
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007036 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007037 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007038
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007039 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007040}
7041
Johan Hedberg744cf192011-11-08 20:40:14 +02007042int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007043 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007044{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007045 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007046 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007047}
7048
Johan Hedberg272d90d2012-02-09 15:26:12 +02007049int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007050 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007051{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007052 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007053 status,
7054 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007055}
Johan Hedberg2a611692011-02-19 12:06:00 -03007056
Brian Gix604086b2011-11-23 08:28:33 -08007057int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007058 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007059{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007060 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007061 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007062}
7063
Johan Hedberg272d90d2012-02-09 15:26:12 +02007064int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007065 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007066{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007067 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007068 status,
7069 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007070}
7071
Johan Hedberg92a25252012-09-06 18:39:26 +03007072int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7073 u8 link_type, u8 addr_type, u32 passkey,
7074 u8 entered)
7075{
7076 struct mgmt_ev_passkey_notify ev;
7077
7078 BT_DBG("%s", hdev->name);
7079
7080 bacpy(&ev.addr.bdaddr, bdaddr);
7081 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7082 ev.passkey = __cpu_to_le32(passkey);
7083 ev.entered = entered;
7084
7085 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7086}
7087
Johan Hedberge1e930f2014-09-08 17:09:49 -07007088void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007089{
7090 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007091 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007092 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007093
Johan Hedberge1e930f2014-09-08 17:09:49 -07007094 bacpy(&ev.addr.bdaddr, &conn->dst);
7095 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7096 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007097
Johan Hedberge1e930f2014-09-08 17:09:49 -07007098 cmd = find_pairing(conn);
7099
7100 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7101 cmd ? cmd->sk : NULL);
7102
Johan Hedberga511b352014-12-11 21:45:45 +02007103 if (cmd) {
7104 cmd->cmd_complete(cmd, status);
7105 mgmt_pending_remove(cmd);
7106 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007107}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007108
Marcel Holtmann464996a2013-10-15 14:26:24 -07007109void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007110{
7111 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007112 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007113
7114 if (status) {
7115 u8 mgmt_err = mgmt_status(status);
7116 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007117 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007118 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007119 }
7120
Marcel Holtmann464996a2013-10-15 14:26:24 -07007121 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007122 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007123 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007124 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007125
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007126 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007127 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007128
Johan Hedberg47990ea2012-02-22 11:58:37 +02007129 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007130 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007131
7132 if (match.sk)
7133 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007134}
7135
Johan Hedberg890ea892013-03-15 17:06:52 -05007136static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007137{
Johan Hedberg890ea892013-03-15 17:06:52 -05007138 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007139 struct hci_cp_write_eir cp;
7140
Johan Hedberg976eb202012-10-24 21:12:01 +03007141 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007142 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007143
Johan Hedbergc80da272012-02-22 15:38:48 +02007144 memset(hdev->eir, 0, sizeof(hdev->eir));
7145
Johan Hedbergcacaf522012-02-21 00:52:42 +02007146 memset(&cp, 0, sizeof(cp));
7147
Johan Hedberg890ea892013-03-15 17:06:52 -05007148 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007149}
7150
Marcel Holtmann3e248562013-10-15 14:26:25 -07007151void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007152{
7153 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007154 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007155 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007156
7157 if (status) {
7158 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007159
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007160 if (enable && hci_dev_test_and_clear_flag(hdev,
7161 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007162 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007163 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007164 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007165
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007166 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7167 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007168 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007169 }
7170
7171 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007172 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007173 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007174 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007175 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007176 changed = hci_dev_test_and_clear_flag(hdev,
7177 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007178 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007179 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007180 }
7181
7182 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7183
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007184 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007185 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007186
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007187 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007188 sock_put(match.sk);
7189
Johan Hedberg890ea892013-03-15 17:06:52 -05007190 hci_req_init(&req, hdev);
7191
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007192 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7193 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007194 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7195 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007196 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007197 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007198 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007199 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007200
7201 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007202}
7203
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007204static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007205{
7206 struct cmd_lookup *match = data;
7207
Johan Hedberg90e70452012-02-23 23:09:40 +02007208 if (match->sk == NULL) {
7209 match->sk = cmd->sk;
7210 sock_hold(match->sk);
7211 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007212}
7213
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007214void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7215 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007216{
Johan Hedberg90e70452012-02-23 23:09:40 +02007217 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007218
Johan Hedberg92da6092013-03-15 17:06:55 -05007219 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7220 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7221 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007222
7223 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007224 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7225 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007226
7227 if (match.sk)
7228 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007229}
7230
Marcel Holtmann7667da32013-10-15 14:26:27 -07007231void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007232{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007233 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007234 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007235
Johan Hedberg13928972013-03-15 17:07:00 -05007236 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007237 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007238
7239 memset(&ev, 0, sizeof(ev));
7240 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007241 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007242
Johan Hedberg333ae952015-03-17 13:48:47 +02007243 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007244 if (!cmd) {
7245 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007246
Johan Hedberg13928972013-03-15 17:07:00 -05007247 /* If this is a HCI command related to powering on the
7248 * HCI dev don't send any mgmt signals.
7249 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007250 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007251 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007252 }
7253
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007254 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7255 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007256}
Szymon Jancc35938b2011-03-22 13:12:21 +01007257
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007258static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7259{
7260 int i;
7261
7262 for (i = 0; i < uuid_count; i++) {
7263 if (!memcmp(uuid, uuids[i], 16))
7264 return true;
7265 }
7266
7267 return false;
7268}
7269
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007270static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7271{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007272 u16 parsed = 0;
7273
7274 while (parsed < eir_len) {
7275 u8 field_len = eir[0];
7276 u8 uuid[16];
7277 int i;
7278
7279 if (field_len == 0)
7280 break;
7281
7282 if (eir_len - parsed < field_len + 1)
7283 break;
7284
7285 switch (eir[1]) {
7286 case EIR_UUID16_ALL:
7287 case EIR_UUID16_SOME:
7288 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007289 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007290 uuid[13] = eir[i + 3];
7291 uuid[12] = eir[i + 2];
7292 if (has_uuid(uuid, uuid_count, uuids))
7293 return true;
7294 }
7295 break;
7296 case EIR_UUID32_ALL:
7297 case EIR_UUID32_SOME:
7298 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007299 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007300 uuid[15] = eir[i + 5];
7301 uuid[14] = eir[i + 4];
7302 uuid[13] = eir[i + 3];
7303 uuid[12] = eir[i + 2];
7304 if (has_uuid(uuid, uuid_count, uuids))
7305 return true;
7306 }
7307 break;
7308 case EIR_UUID128_ALL:
7309 case EIR_UUID128_SOME:
7310 for (i = 0; i + 17 <= field_len; i += 16) {
7311 memcpy(uuid, eir + i + 2, 16);
7312 if (has_uuid(uuid, uuid_count, uuids))
7313 return true;
7314 }
7315 break;
7316 }
7317
7318 parsed += field_len + 1;
7319 eir += field_len + 1;
7320 }
7321
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007322 return false;
7323}
7324
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007325static void restart_le_scan(struct hci_dev *hdev)
7326{
7327 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007328 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007329 return;
7330
7331 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7332 hdev->discovery.scan_start +
7333 hdev->discovery.scan_duration))
7334 return;
7335
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007336 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007337 DISCOV_LE_RESTART_DELAY);
7338}
7339
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007340static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7341 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7342{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007343 /* If a RSSI threshold has been specified, and
7344 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7345 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7346 * is set, let it through for further processing, as we might need to
7347 * restart the scan.
7348 *
7349 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7350 * the results are also dropped.
7351 */
7352 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7353 (rssi == HCI_RSSI_INVALID ||
7354 (rssi < hdev->discovery.rssi &&
7355 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7356 return false;
7357
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007358 if (hdev->discovery.uuid_count != 0) {
7359 /* If a list of UUIDs is provided in filter, results with no
7360 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007361 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007362 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7363 hdev->discovery.uuids) &&
7364 !eir_has_uuids(scan_rsp, scan_rsp_len,
7365 hdev->discovery.uuid_count,
7366 hdev->discovery.uuids))
7367 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007368 }
7369
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007370 /* If duplicate filtering does not report RSSI changes, then restart
7371 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007372 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007373 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7374 restart_le_scan(hdev);
7375
7376 /* Validate RSSI value against the RSSI threshold once more. */
7377 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7378 rssi < hdev->discovery.rssi)
7379 return false;
7380 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007381
7382 return true;
7383}
7384
Marcel Holtmann901801b2013-10-06 23:55:51 -07007385void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007386 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7387 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007388{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007389 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007390 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007391 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007392
Johan Hedberg75ce2082014-07-02 22:42:01 +03007393 /* Don't send events for a non-kernel initiated discovery. With
7394 * LE one exception is if we have pend_le_reports > 0 in which
7395 * case we're doing passive scanning and want these events.
7396 */
7397 if (!hci_discovery_active(hdev)) {
7398 if (link_type == ACL_LINK)
7399 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007400 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007401 return;
7402 }
Andre Guedes12602d02013-04-30 15:29:40 -03007403
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007404 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007405 /* We are using service discovery */
7406 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7407 scan_rsp_len))
7408 return;
7409 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007410
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007411 /* Make sure that the buffer is big enough. The 5 extra bytes
7412 * are for the potential CoD field.
7413 */
7414 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007415 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007416
Johan Hedberg1dc06092012-01-15 21:01:23 +02007417 memset(buf, 0, sizeof(buf));
7418
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007419 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7420 * RSSI value was reported as 0 when not available. This behavior
7421 * is kept when using device discovery. This is required for full
7422 * backwards compatibility with the API.
7423 *
7424 * However when using service discovery, the value 127 will be
7425 * returned when the RSSI is not available.
7426 */
Szymon Janc91200e92015-01-22 16:57:05 +01007427 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7428 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007429 rssi = 0;
7430
Johan Hedberg841c5642014-07-07 12:45:54 +03007431 bacpy(&ev->addr.bdaddr, bdaddr);
7432 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007433 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007434 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007435
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007436 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007437 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007438 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007439
Johan Hedberg1dc06092012-01-15 21:01:23 +02007440 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7441 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007442 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007443
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007444 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007445 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007446 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007447
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007448 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7449 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007450
Marcel Holtmann901801b2013-10-06 23:55:51 -07007451 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007452}
Johan Hedberga88a9652011-03-30 13:18:12 +03007453
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007454void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7455 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007456{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007457 struct mgmt_ev_device_found *ev;
7458 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7459 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007460
Johan Hedbergb644ba32012-01-17 21:48:47 +02007461 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007462
Johan Hedbergb644ba32012-01-17 21:48:47 +02007463 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007464
Johan Hedbergb644ba32012-01-17 21:48:47 +02007465 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007466 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007467 ev->rssi = rssi;
7468
7469 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007470 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007471
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007472 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007473
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007474 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007475}
Johan Hedberg314b2382011-04-27 10:29:57 -04007476
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007477void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007478{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007479 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007480
Andre Guedes343fb142011-11-22 17:14:19 -03007481 BT_DBG("%s discovering %u", hdev->name, discovering);
7482
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007483 memset(&ev, 0, sizeof(ev));
7484 ev.type = hdev->discovery.type;
7485 ev.discovering = discovering;
7486
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007487 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007488}
Antti Julku5e762442011-08-25 16:48:02 +03007489
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007490static struct hci_mgmt_chan chan = {
7491 .channel = HCI_CHANNEL_CONTROL,
7492 .handler_count = ARRAY_SIZE(mgmt_handlers),
7493 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007494 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007495};
7496
7497int mgmt_init(void)
7498{
7499 return hci_mgmt_chan_register(&chan);
7500}
7501
7502void mgmt_exit(void)
7503{
7504 hci_mgmt_chan_unregister(&chan);
7505}