blob: 9ce2bb2fc977ce7499378b16fef8e631dacc8200 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Johan Hedbergdc4270c2015-11-23 15:07:51 +020041#define MGMT_REVISION 11
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
108static const u16 mgmt_events[] = {
109 MGMT_EV_CONTROLLER_ERROR,
110 MGMT_EV_INDEX_ADDED,
111 MGMT_EV_INDEX_REMOVED,
112 MGMT_EV_NEW_SETTINGS,
113 MGMT_EV_CLASS_OF_DEV_CHANGED,
114 MGMT_EV_LOCAL_NAME_CHANGED,
115 MGMT_EV_NEW_LINK_KEY,
116 MGMT_EV_NEW_LONG_TERM_KEY,
117 MGMT_EV_DEVICE_CONNECTED,
118 MGMT_EV_DEVICE_DISCONNECTED,
119 MGMT_EV_CONNECT_FAILED,
120 MGMT_EV_PIN_CODE_REQUEST,
121 MGMT_EV_USER_CONFIRM_REQUEST,
122 MGMT_EV_USER_PASSKEY_REQUEST,
123 MGMT_EV_AUTH_FAILED,
124 MGMT_EV_DEVICE_FOUND,
125 MGMT_EV_DISCOVERING,
126 MGMT_EV_DEVICE_BLOCKED,
127 MGMT_EV_DEVICE_UNBLOCKED,
128 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300129 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800130 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700131 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200132 MGMT_EV_DEVICE_ADDED,
133 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300134 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200135 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200136 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200137 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700138 MGMT_EV_EXT_INDEX_ADDED,
139 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700140 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700141 MGMT_EV_ADVERTISING_ADDED,
142 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200143};
144
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700145static const u16 mgmt_untrusted_commands[] = {
146 MGMT_OP_READ_INDEX_LIST,
147 MGMT_OP_READ_INFO,
148 MGMT_OP_READ_UNCONF_INDEX_LIST,
149 MGMT_OP_READ_CONFIG_INFO,
150 MGMT_OP_READ_EXT_INDEX_LIST,
151};
152
153static const u16 mgmt_untrusted_events[] = {
154 MGMT_EV_INDEX_ADDED,
155 MGMT_EV_INDEX_REMOVED,
156 MGMT_EV_NEW_SETTINGS,
157 MGMT_EV_CLASS_OF_DEV_CHANGED,
158 MGMT_EV_LOCAL_NAME_CHANGED,
159 MGMT_EV_UNCONF_INDEX_ADDED,
160 MGMT_EV_UNCONF_INDEX_REMOVED,
161 MGMT_EV_NEW_CONFIG_OPTIONS,
162 MGMT_EV_EXT_INDEX_ADDED,
163 MGMT_EV_EXT_INDEX_REMOVED,
164};
165
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800166#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200167
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200168#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
169 "\x00\x00\x00\x00\x00\x00\x00\x00"
170
Johan Hedbergca69b792011-11-11 18:10:00 +0200171/* HCI to MGMT error code conversion table */
172static u8 mgmt_status_table[] = {
173 MGMT_STATUS_SUCCESS,
174 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
175 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
176 MGMT_STATUS_FAILED, /* Hardware Failure */
177 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
178 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200179 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200180 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
181 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
182 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
184 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
185 MGMT_STATUS_BUSY, /* Command Disallowed */
186 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
187 MGMT_STATUS_REJECTED, /* Rejected Security */
188 MGMT_STATUS_REJECTED, /* Rejected Personal */
189 MGMT_STATUS_TIMEOUT, /* Host Timeout */
190 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
191 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
192 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
193 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
194 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
195 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
196 MGMT_STATUS_BUSY, /* Repeated Attempts */
197 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
198 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
199 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
200 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
201 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
202 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
203 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
204 MGMT_STATUS_FAILED, /* Unspecified Error */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
206 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
207 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
208 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
209 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
210 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
211 MGMT_STATUS_FAILED, /* Unit Link Key Used */
212 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
213 MGMT_STATUS_TIMEOUT, /* Instant Passed */
214 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
215 MGMT_STATUS_FAILED, /* Transaction Collision */
216 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
217 MGMT_STATUS_REJECTED, /* QoS Rejected */
218 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
219 MGMT_STATUS_REJECTED, /* Insufficient Security */
220 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
221 MGMT_STATUS_BUSY, /* Role Switch Pending */
222 MGMT_STATUS_FAILED, /* Slot Violation */
223 MGMT_STATUS_FAILED, /* Role Switch Failed */
224 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
225 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
226 MGMT_STATUS_BUSY, /* Host Busy Pairing */
227 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
228 MGMT_STATUS_BUSY, /* Controller Busy */
229 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
230 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
231 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
232 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
233 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
234};
235
236static u8 mgmt_status(u8 hci_status)
237{
238 if (hci_status < ARRAY_SIZE(mgmt_status_table))
239 return mgmt_status_table[hci_status];
240
241 return MGMT_STATUS_FAILED;
242}
243
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700244static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
245 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700246{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700247 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
248 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700249}
250
Marcel Holtmann72000df2015-03-16 16:11:21 -0700251static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
252 u16 len, int flag, struct sock *skip_sk)
253{
254 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
255 flag, skip_sk);
256}
257
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700258static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
259 u16 len, struct sock *skip_sk)
260{
261 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
262 HCI_MGMT_GENERIC_EVENTS, skip_sk);
263}
264
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200265static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
266 struct sock *skip_sk)
267{
268 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700269 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200270}
271
Johan Hedberg85813a72015-10-21 18:02:59 +0300272static u8 le_addr_type(u8 mgmt_addr_type)
273{
274 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
275 return ADDR_LE_DEV_PUBLIC;
276 else
277 return ADDR_LE_DEV_RANDOM;
278}
279
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300280static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
281 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200282{
283 struct mgmt_rp_read_version rp;
284
285 BT_DBG("sock %p", sk);
286
287 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700288 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200289
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200290 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
291 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200292}
293
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300294static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
295 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296{
297 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700298 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200299 size_t rp_size;
300 int i, err;
301
302 BT_DBG("sock %p", sk);
303
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
305 num_commands = ARRAY_SIZE(mgmt_commands);
306 num_events = ARRAY_SIZE(mgmt_events);
307 } else {
308 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
309 num_events = ARRAY_SIZE(mgmt_untrusted_events);
310 }
311
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
313
314 rp = kmalloc(rp_size, GFP_KERNEL);
315 if (!rp)
316 return -ENOMEM;
317
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700318 rp->num_commands = cpu_to_le16(num_commands);
319 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700321 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
322 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200323
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700324 for (i = 0; i < num_commands; i++, opcode++)
325 put_unaligned_le16(mgmt_commands[i], opcode);
326
327 for (i = 0; i < num_events; i++, opcode++)
328 put_unaligned_le16(mgmt_events[i], opcode);
329 } else {
330 __le16 *opcode = rp->opcodes;
331
332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
337 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200338
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200339 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
340 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200341 kfree(rp);
342
343 return err;
344}
345
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300346static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
347 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200351 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
355 BT_DBG("sock %p", sk);
356
357 read_lock(&hci_dev_list_lock);
358
359 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300360 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200361 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700362 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700363 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364 }
365
Johan Hedberga38528f2011-01-22 06:46:43 +0200366 rp_len = sizeof(*rp) + (2 * count);
367 rp = kmalloc(rp_len, GFP_ATOMIC);
368 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100369 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100371 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372
Johan Hedberg476e44c2012-10-19 20:10:46 +0300373 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200374 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700375 if (hci_dev_test_flag(d, HCI_SETUP) ||
376 hci_dev_test_flag(d, HCI_CONFIG) ||
377 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200378 continue;
379
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200380 /* Devices marked as raw-only are neither configured
381 * nor unconfigured controllers.
382 */
383 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700387 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700388 rp->index[count++] = cpu_to_le16(d->id);
389 BT_DBG("Added hci%u", d->id);
390 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391 }
392
Johan Hedberg476e44c2012-10-19 20:10:46 +0300393 rp->num_controllers = cpu_to_le16(count);
394 rp_len = sizeof(*rp) + (2 * count);
395
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 read_unlock(&hci_dev_list_lock);
397
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200398 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
399 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400
Johan Hedberga38528f2011-01-22 06:46:43 +0200401 kfree(rp);
402
403 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404}
405
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200406static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
407 void *data, u16 data_len)
408{
409 struct mgmt_rp_read_unconf_index_list *rp;
410 struct hci_dev *d;
411 size_t rp_len;
412 u16 count;
413 int err;
414
415 BT_DBG("sock %p", sk);
416
417 read_lock(&hci_dev_list_lock);
418
419 count = 0;
420 list_for_each_entry(d, &hci_dev_list, list) {
421 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700422 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200423 count++;
424 }
425
426 rp_len = sizeof(*rp) + (2 * count);
427 rp = kmalloc(rp_len, GFP_ATOMIC);
428 if (!rp) {
429 read_unlock(&hci_dev_list_lock);
430 return -ENOMEM;
431 }
432
433 count = 0;
434 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700435 if (hci_dev_test_flag(d, HCI_SETUP) ||
436 hci_dev_test_flag(d, HCI_CONFIG) ||
437 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438 continue;
439
440 /* Devices marked as raw-only are neither configured
441 * nor unconfigured controllers.
442 */
443 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
444 continue;
445
446 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700447 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448 rp->index[count++] = cpu_to_le16(d->id);
449 BT_DBG("Added hci%u", d->id);
450 }
451 }
452
453 rp->num_controllers = cpu_to_le16(count);
454 rp_len = sizeof(*rp) + (2 * count);
455
456 read_unlock(&hci_dev_list_lock);
457
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200458 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
459 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200460
461 kfree(rp);
462
463 return err;
464}
465
Marcel Holtmann96f14742015-03-14 19:27:57 -0700466static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
467 void *data, u16 data_len)
468{
469 struct mgmt_rp_read_ext_index_list *rp;
470 struct hci_dev *d;
471 size_t rp_len;
472 u16 count;
473 int err;
474
475 BT_DBG("sock %p", sk);
476
477 read_lock(&hci_dev_list_lock);
478
479 count = 0;
480 list_for_each_entry(d, &hci_dev_list, list) {
481 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
482 count++;
483 }
484
485 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
486 rp = kmalloc(rp_len, GFP_ATOMIC);
487 if (!rp) {
488 read_unlock(&hci_dev_list_lock);
489 return -ENOMEM;
490 }
491
492 count = 0;
493 list_for_each_entry(d, &hci_dev_list, list) {
494 if (hci_dev_test_flag(d, HCI_SETUP) ||
495 hci_dev_test_flag(d, HCI_CONFIG) ||
496 hci_dev_test_flag(d, HCI_USER_CHANNEL))
497 continue;
498
499 /* Devices marked as raw-only are neither configured
500 * nor unconfigured controllers.
501 */
502 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
503 continue;
504
505 if (d->dev_type == HCI_BREDR) {
506 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
507 rp->entry[count].type = 0x01;
508 else
509 rp->entry[count].type = 0x00;
510 } else if (d->dev_type == HCI_AMP) {
511 rp->entry[count].type = 0x02;
512 } else {
513 continue;
514 }
515
516 rp->entry[count].bus = d->bus;
517 rp->entry[count++].index = cpu_to_le16(d->id);
518 BT_DBG("Added hci%u", d->id);
519 }
520
521 rp->num_controllers = cpu_to_le16(count);
522 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
523
524 read_unlock(&hci_dev_list_lock);
525
526 /* If this command is called at least once, then all the
527 * default index and unconfigured index events are disabled
528 * and from now on only extended index events are used.
529 */
530 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
531 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
532 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
533
534 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
535 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
536
537 kfree(rp);
538
539 return err;
540}
541
Marcel Holtmanndbece372014-07-04 18:11:55 +0200542static bool is_configured(struct hci_dev *hdev)
543{
544 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700545 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200546 return false;
547
548 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
549 !bacmp(&hdev->public_addr, BDADDR_ANY))
550 return false;
551
552 return true;
553}
554
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200555static __le32 get_missing_options(struct hci_dev *hdev)
556{
557 u32 options = 0;
558
Marcel Holtmanndbece372014-07-04 18:11:55 +0200559 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700560 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200561 options |= MGMT_OPTION_EXTERNAL_CONFIG;
562
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200563 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
564 !bacmp(&hdev->public_addr, BDADDR_ANY))
565 options |= MGMT_OPTION_PUBLIC_ADDRESS;
566
567 return cpu_to_le32(options);
568}
569
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200570static int new_options(struct hci_dev *hdev, struct sock *skip)
571{
572 __le32 options = get_missing_options(hdev);
573
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700574 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
575 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576}
577
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
579{
580 __le32 options = get_missing_options(hdev);
581
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200582 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
583 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584}
585
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200586static int read_config_info(struct sock *sk, struct hci_dev *hdev,
587 void *data, u16 data_len)
588{
589 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200590 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591
592 BT_DBG("sock %p %s", sk, hdev->name);
593
594 hci_dev_lock(hdev);
595
596 memset(&rp, 0, sizeof(rp));
597 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
600 options |= MGMT_OPTION_EXTERNAL_CONFIG;
601
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200602 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603 options |= MGMT_OPTION_PUBLIC_ADDRESS;
604
605 rp.supported_options = cpu_to_le32(options);
606 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607
608 hci_dev_unlock(hdev);
609
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
611 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612}
613
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200614static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200615{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200617
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300619 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800620 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300621 settings |= MGMT_SETTING_CONNECTABLE;
622 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Andre Guedesed3fa312012-07-24 15:03:46 -0300624 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500625 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
626 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627 settings |= MGMT_SETTING_BREDR;
628 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700629
630 if (lmp_ssp_capable(hdev)) {
631 settings |= MGMT_SETTING_SSP;
632 settings |= MGMT_SETTING_HS;
633 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800634
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800635 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800636 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700637 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100638
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300639 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200640 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300641 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300642 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200643 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800644 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300645 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200646
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200647 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
648 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200649 settings |= MGMT_SETTING_CONFIGURATION;
650
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651 return settings;
652}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200653
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200654static u32 get_current_settings(struct hci_dev *hdev)
655{
656 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200657
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200658 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100659 settings |= MGMT_SETTING_POWERED;
660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662 settings |= MGMT_SETTING_CONNECTABLE;
663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700664 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500665 settings |= MGMT_SETTING_FAST_CONNECTABLE;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_DISCOVERABLE;
669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300671 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_BREDR;
675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200683 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200686 settings |= MGMT_SETTING_HS;
687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300689 settings |= MGMT_SETTING_ADVERTISING;
690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700691 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800692 settings |= MGMT_SETTING_SECURE_CONN;
693
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700694 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800695 settings |= MGMT_SETTING_DEBUG_KEYS;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200698 settings |= MGMT_SETTING_PRIVACY;
699
Marcel Holtmann93690c22015-03-06 10:11:21 -0800700 /* The current setting for static address has two purposes. The
701 * first is to indicate if the static address will be used and
702 * the second is to indicate if it is actually set.
703 *
704 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700705 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800706 * address is actually used decides if the flag is set or not.
707 *
708 * For single mode LE only controllers and dual-mode controllers
709 * with BR/EDR disabled, the existence of the static address will
710 * be evaluated.
711 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700712 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700713 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800714 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
715 if (bacmp(&hdev->static_addr, BDADDR_ANY))
716 settings |= MGMT_SETTING_STATIC_ADDRESS;
717 }
718
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200720}
721
Johan 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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300858 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200964 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200965 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966 goto failed;
967 }
968
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200969 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
970 if (!cmd) {
971 err = -ENOMEM;
972 goto failed;
973 }
974
Johan Hedberg8b064a32014-02-24 14:52:22 +0200975 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +0200976 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200977 err = 0;
978 } else {
979 /* Disconnect connections, stop scans, etc */
980 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +0200981 if (!err)
982 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
983 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984
Johan Hedberg8b064a32014-02-24 14:52:22 +0200985 /* ENODATA means there were no HCI commands queued */
986 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +0200987 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200988 queue_work(hdev->req_workqueue, &hdev->power_off.work);
989 err = 0;
990 }
991 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200992
993failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300994 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200995 return err;
996}
997
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200998static int new_settings(struct hci_dev *hdev, struct sock *skip)
999{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001000 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001001
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001002 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1003 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001004}
1005
Johan Hedberg91a668b2014-07-09 13:28:26 +03001006int mgmt_new_settings(struct hci_dev *hdev)
1007{
1008 return new_settings(hdev, NULL);
1009}
1010
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001011struct cmd_lookup {
1012 struct sock *sk;
1013 struct hci_dev *hdev;
1014 u8 mgmt_status;
1015};
1016
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001017static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001018{
1019 struct cmd_lookup *match = data;
1020
1021 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1022
1023 list_del(&cmd->list);
1024
1025 if (match->sk == NULL) {
1026 match->sk = cmd->sk;
1027 sock_hold(match->sk);
1028 }
1029
1030 mgmt_pending_free(cmd);
1031}
1032
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001033static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001034{
1035 u8 *status = data;
1036
Johan Hedberga69e8372015-03-06 21:08:53 +02001037 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001038 mgmt_pending_remove(cmd);
1039}
1040
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001041static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001042{
1043 if (cmd->cmd_complete) {
1044 u8 *status = data;
1045
1046 cmd->cmd_complete(cmd, *status);
1047 mgmt_pending_remove(cmd);
1048
1049 return;
1050 }
1051
1052 cmd_status_rsp(cmd, data);
1053}
1054
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001055static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001056{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001057 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1058 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001059}
1060
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001061static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001062{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001063 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1064 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001065}
1066
Johan Hedberge6fe7982013-10-02 15:45:22 +03001067static u8 mgmt_bredr_support(struct hci_dev *hdev)
1068{
1069 if (!lmp_bredr_capable(hdev))
1070 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001071 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001072 return MGMT_STATUS_REJECTED;
1073 else
1074 return MGMT_STATUS_SUCCESS;
1075}
1076
1077static u8 mgmt_le_support(struct hci_dev *hdev)
1078{
1079 if (!lmp_le_capable(hdev))
1080 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001081 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001082 return MGMT_STATUS_REJECTED;
1083 else
1084 return MGMT_STATUS_SUCCESS;
1085}
1086
Johan Hedbergaed1a882015-11-22 17:24:44 +03001087void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001088{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001089 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001090
1091 BT_DBG("status 0x%02x", status);
1092
1093 hci_dev_lock(hdev);
1094
Johan Hedberg333ae952015-03-17 13:48:47 +02001095 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001096 if (!cmd)
1097 goto unlock;
1098
1099 if (status) {
1100 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001101 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001102 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001103 goto remove_cmd;
1104 }
1105
Johan Hedbergaed1a882015-11-22 17:24:44 +03001106 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1107 hdev->discov_timeout > 0) {
1108 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1109 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001110 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001111
1112 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001113 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001114
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001115remove_cmd:
1116 mgmt_pending_remove(cmd);
1117
1118unlock:
1119 hci_dev_unlock(hdev);
1120}
1121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001122static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001123 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001124{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001125 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001126 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001127 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001128 int err;
1129
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001130 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001131
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001132 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1133 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001134 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1135 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001136
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001137 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001138 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1139 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001140
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001141 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001142
1143 /* Disabling discoverable requires that no timeout is set,
1144 * and enabling limited discoverable requires a timeout.
1145 */
1146 if ((cp->val == 0x00 && timeout > 0) ||
1147 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001148 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1149 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001151 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001152
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001153 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001154 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1155 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001156 goto failed;
1157 }
1158
Johan Hedberg333ae952015-03-17 13:48:47 +02001159 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1160 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001161 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1162 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001163 goto failed;
1164 }
1165
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001166 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001167 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1168 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001169 goto failed;
1170 }
1171
1172 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001173 bool changed = false;
1174
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001175 /* Setting limited discoverable when powered off is
1176 * not a valid operation since it requires a timeout
1177 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1178 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001179 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001180 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001181 changed = true;
1182 }
1183
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001184 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001185 if (err < 0)
1186 goto failed;
1187
1188 if (changed)
1189 err = new_settings(hdev, sk);
1190
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001191 goto failed;
1192 }
1193
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001194 /* If the current mode is the same, then just update the timeout
1195 * value with the new value. And if only the timeout gets updated,
1196 * then no need for any HCI transactions.
1197 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001198 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1199 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1200 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001201 cancel_delayed_work(&hdev->discov_off);
1202 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001203
Marcel Holtmann36261542013-10-15 08:28:51 -07001204 if (cp->val && hdev->discov_timeout > 0) {
1205 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001206 queue_delayed_work(hdev->req_workqueue,
1207 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001208 }
1209
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001210 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 goto failed;
1212 }
1213
1214 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1215 if (!cmd) {
1216 err = -ENOMEM;
1217 goto failed;
1218 }
1219
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001220 /* Cancel any potential discoverable timeout that might be
1221 * still active and store new timeout value. The arming of
1222 * the timeout happens in the complete handler.
1223 */
1224 cancel_delayed_work(&hdev->discov_off);
1225 hdev->discov_timeout = timeout;
1226
Johan Hedbergaed1a882015-11-22 17:24:44 +03001227 if (cp->val)
1228 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1229 else
1230 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1231
Johan Hedbergb456f872013-10-19 23:38:22 +03001232 /* Limited discoverable mode */
1233 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001234 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001235 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001236 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001237
Johan Hedbergaed1a882015-11-22 17:24:44 +03001238 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1239 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001240
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001241failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001242 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001243 return err;
1244}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001245
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001246void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001247{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001248 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001249
1250 BT_DBG("status 0x%02x", status);
1251
1252 hci_dev_lock(hdev);
1253
Johan Hedberg333ae952015-03-17 13:48:47 +02001254 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001255 if (!cmd)
1256 goto unlock;
1257
Johan Hedberg37438c12013-10-14 16:20:05 +03001258 if (status) {
1259 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001260 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001261 goto remove_cmd;
1262 }
1263
Johan Hedberg2b76f452013-03-15 17:07:04 -05001264 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001265 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001266
Johan Hedberg37438c12013-10-14 16:20:05 +03001267remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001268 mgmt_pending_remove(cmd);
1269
1270unlock:
1271 hci_dev_unlock(hdev);
1272}
1273
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001274static int set_connectable_update_settings(struct hci_dev *hdev,
1275 struct sock *sk, u8 val)
1276{
1277 bool changed = false;
1278 int err;
1279
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001280 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001281 changed = true;
1282
1283 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001284 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001285 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001286 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1287 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001288 }
1289
1290 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1291 if (err < 0)
1292 return err;
1293
Johan Hedberg562064e2014-07-08 16:35:34 +03001294 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001295 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001296 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001297 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001298 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001299
1300 return 0;
1301}
1302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001303static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001304 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001305{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001306 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001307 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001308 int err;
1309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001310 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001311
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001312 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1313 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1315 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001316
Johan Hedberga7e80f22013-01-09 16:05:19 +02001317 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001318 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1319 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001320
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001321 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001322
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001323 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001324 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001325 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001326 }
1327
Johan Hedberg333ae952015-03-17 13:48:47 +02001328 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1329 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001330 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1331 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001332 goto failed;
1333 }
1334
Johan Hedberg73f22f62010-12-29 16:00:25 +02001335 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1336 if (!cmd) {
1337 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001338 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001339 }
1340
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001341 if (cp->val) {
1342 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1343 } else {
1344 if (hdev->discov_timeout > 0)
1345 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001346
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001347 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1348 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1349 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001350 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001351
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001352 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1353 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001354
1355failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001356 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001357 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001358}
1359
Johan Hedbergb2939472014-07-30 09:22:23 +03001360static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001361 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001362{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001363 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001364 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001365 int err;
1366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001367 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001368
Johan Hedberga7e80f22013-01-09 16:05:19 +02001369 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001370 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1371 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001372
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001373 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001374
1375 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001376 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001377 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001378 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001379
Johan Hedbergb2939472014-07-30 09:22:23 +03001380 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001381 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001382 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001383
Marcel Holtmann55594352013-10-06 16:11:57 -07001384 if (changed)
1385 err = new_settings(hdev, sk);
Johan Hedberg053f0212011-01-26 13:07:10 +02001386
Marcel Holtmann55594352013-10-06 16:11:57 -07001387unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001388 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001389 return err;
1390}
1391
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001392static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1393 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001394{
1395 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001396 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001397 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001398 int err;
1399
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001400 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001401
Johan Hedberge6fe7982013-10-02 15:45:22 +03001402 status = mgmt_bredr_support(hdev);
1403 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001404 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1405 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001406
Johan Hedberga7e80f22013-01-09 16:05:19 +02001407 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001408 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1409 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001410
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001411 hci_dev_lock(hdev);
1412
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001413 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001414 bool changed = false;
1415
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001416 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001417 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001418 changed = true;
1419 }
1420
1421 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1422 if (err < 0)
1423 goto failed;
1424
1425 if (changed)
1426 err = new_settings(hdev, sk);
1427
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001428 goto failed;
1429 }
1430
Johan Hedberg333ae952015-03-17 13:48:47 +02001431 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001432 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1433 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001434 goto failed;
1435 }
1436
1437 val = !!cp->val;
1438
1439 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1440 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1441 goto failed;
1442 }
1443
1444 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1445 if (!cmd) {
1446 err = -ENOMEM;
1447 goto failed;
1448 }
1449
1450 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1451 if (err < 0) {
1452 mgmt_pending_remove(cmd);
1453 goto failed;
1454 }
1455
1456failed:
1457 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001458 return err;
1459}
1460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001461static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001462{
1463 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001464 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001465 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001466 int err;
1467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001468 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001469
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001470 status = mgmt_bredr_support(hdev);
1471 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001472 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001473
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001474 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001475 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1476 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001477
Johan Hedberga7e80f22013-01-09 16:05:19 +02001478 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001479 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1480 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001481
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001482 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001483
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001484 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001485 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001486
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001487 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001488 changed = !hci_dev_test_and_set_flag(hdev,
1489 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001490 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001491 changed = hci_dev_test_and_clear_flag(hdev,
1492 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001493 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001494 changed = hci_dev_test_and_clear_flag(hdev,
1495 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001496 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001497 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001498 }
1499
1500 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1501 if (err < 0)
1502 goto failed;
1503
1504 if (changed)
1505 err = new_settings(hdev, sk);
1506
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001507 goto failed;
1508 }
1509
Johan Hedberg333ae952015-03-17 13:48:47 +02001510 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001511 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1512 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001513 goto failed;
1514 }
1515
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001516 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001517 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1518 goto failed;
1519 }
1520
1521 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1522 if (!cmd) {
1523 err = -ENOMEM;
1524 goto failed;
1525 }
1526
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001527 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001528 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1529 sizeof(cp->val), &cp->val);
1530
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001531 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001532 if (err < 0) {
1533 mgmt_pending_remove(cmd);
1534 goto failed;
1535 }
1536
1537failed:
1538 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001539 return err;
1540}
1541
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001542static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001543{
1544 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001545 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001546 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001547 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001550
Johan Hedberge6fe7982013-10-02 15:45:22 +03001551 status = mgmt_bredr_support(hdev);
1552 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001553 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001554
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001555 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001556 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1557 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001558
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001559 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001560 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1561 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001562
Johan Hedberga7e80f22013-01-09 16:05:19 +02001563 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001564 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1565 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001566
Marcel Holtmannee392692013-10-01 22:59:23 -07001567 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001568
Johan Hedberg333ae952015-03-17 13:48:47 +02001569 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001570 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1571 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001572 goto unlock;
1573 }
1574
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001575 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001576 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001577 } else {
1578 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001579 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1580 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001581 goto unlock;
1582 }
1583
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001584 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001585 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001586
1587 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1588 if (err < 0)
1589 goto unlock;
1590
1591 if (changed)
1592 err = new_settings(hdev, sk);
1593
1594unlock:
1595 hci_dev_unlock(hdev);
1596 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001597}
1598
Marcel Holtmann1904a852015-01-11 13:50:44 -08001599static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001600{
1601 struct cmd_lookup match = { NULL, hdev };
1602
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301603 hci_dev_lock(hdev);
1604
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001605 if (status) {
1606 u8 mgmt_err = mgmt_status(status);
1607
1608 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1609 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301610 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001611 }
1612
1613 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1614
1615 new_settings(hdev, match.sk);
1616
1617 if (match.sk)
1618 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001619
1620 /* Make sure the controller has a good default for
1621 * advertising data. Restrict the update to when LE
1622 * has actually been enabled. During power on, the
1623 * update in powered_update_hci will take care of it.
1624 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001625 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001626 struct hci_request req;
1627
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001628 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001629 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
1630 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001631 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001632 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001633 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301634
1635unlock:
1636 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001637}
1638
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001639static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001640{
1641 struct mgmt_mode *cp = data;
1642 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001643 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001644 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001645 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001646 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001648 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001649
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001650 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001651 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1652 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001653
Johan Hedberga7e80f22013-01-09 16:05:19 +02001654 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001655 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1656 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001657
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001658 /* Bluetooth single mode LE only controllers or dual-mode
1659 * controllers configured as LE only devices, do not allow
1660 * switching LE off. These have either LE enabled explicitly
1661 * or BR/EDR has been previously switched off.
1662 *
1663 * When trying to enable an already enabled LE, then gracefully
1664 * send a positive response. Trying to disable it however will
1665 * result into rejection.
1666 */
1667 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1668 if (cp->val == 0x01)
1669 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1670
Johan Hedberga69e8372015-03-06 21:08:53 +02001671 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1672 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001673 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001674
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001675 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001676
1677 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001678 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001679
Florian Grandel847818d2015-06-18 03:16:46 +02001680 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02001681 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001682
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001683 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001684 bool changed = false;
1685
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001686 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001687 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001688 changed = true;
1689 }
1690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001691 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001692 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001693 changed = true;
1694 }
1695
Johan Hedberg06199cf2012-02-22 16:37:11 +02001696 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1697 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001698 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001699
1700 if (changed)
1701 err = new_settings(hdev, sk);
1702
Johan Hedberg1de028c2012-02-29 19:55:35 -08001703 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001704 }
1705
Johan Hedberg333ae952015-03-17 13:48:47 +02001706 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1707 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001708 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1709 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001710 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001711 }
1712
1713 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1714 if (!cmd) {
1715 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001716 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001717 }
1718
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001719 hci_req_init(&req, hdev);
1720
Johan Hedberg06199cf2012-02-22 16:37:11 +02001721 memset(&hci_cp, 0, sizeof(hci_cp));
1722
1723 if (val) {
1724 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001725 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001726 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001727 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001728 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001729 }
1730
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001731 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1732 &hci_cp);
1733
1734 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301735 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001736 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001737
Johan Hedberg1de028c2012-02-29 19:55:35 -08001738unlock:
1739 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001740 return err;
1741}
1742
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001743/* This is a helper function to test for pending mgmt commands that can
1744 * cause CoD or EIR HCI commands. We can only allow one such pending
1745 * mgmt command at a time since otherwise we cannot easily track what
1746 * the current values are, will be, and based on that calculate if a new
1747 * HCI command needs to be sent and if yes with what value.
1748 */
1749static bool pending_eir_or_class(struct hci_dev *hdev)
1750{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001751 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001752
1753 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1754 switch (cmd->opcode) {
1755 case MGMT_OP_ADD_UUID:
1756 case MGMT_OP_REMOVE_UUID:
1757 case MGMT_OP_SET_DEV_CLASS:
1758 case MGMT_OP_SET_POWERED:
1759 return true;
1760 }
1761 }
1762
1763 return false;
1764}
1765
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001766static const u8 bluetooth_base_uuid[] = {
1767 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1768 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1769};
1770
1771static u8 get_uuid_size(const u8 *uuid)
1772{
1773 u32 val;
1774
1775 if (memcmp(uuid, bluetooth_base_uuid, 12))
1776 return 128;
1777
1778 val = get_unaligned_le32(&uuid[12]);
1779 if (val > 0xffff)
1780 return 32;
1781
1782 return 16;
1783}
1784
Johan Hedberg92da6092013-03-15 17:06:55 -05001785static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1786{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001787 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001788
1789 hci_dev_lock(hdev);
1790
Johan Hedberg333ae952015-03-17 13:48:47 +02001791 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001792 if (!cmd)
1793 goto unlock;
1794
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001795 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1796 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001797
1798 mgmt_pending_remove(cmd);
1799
1800unlock:
1801 hci_dev_unlock(hdev);
1802}
1803
Marcel Holtmann1904a852015-01-11 13:50:44 -08001804static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001805{
1806 BT_DBG("status 0x%02x", status);
1807
1808 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1809}
1810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001812{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001813 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001814 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001815 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001816 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001817 int err;
1818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001819 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001820
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001821 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001822
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001823 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001824 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1825 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001826 goto failed;
1827 }
1828
Andre Guedes92c4c202012-06-07 19:05:44 -03001829 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001830 if (!uuid) {
1831 err = -ENOMEM;
1832 goto failed;
1833 }
1834
1835 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001836 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001837 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001838
Johan Hedbergde66aa62013-01-27 00:31:27 +02001839 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001840
Johan Hedberg890ea892013-03-15 17:06:52 -05001841 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001842
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001843 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001844 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001845
Johan Hedberg92da6092013-03-15 17:06:55 -05001846 err = hci_req_run(&req, add_uuid_complete);
1847 if (err < 0) {
1848 if (err != -ENODATA)
1849 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001850
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001851 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1852 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001853 goto failed;
1854 }
1855
1856 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001857 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001858 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001859 goto failed;
1860 }
1861
1862 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001863
1864failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001865 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001866 return err;
1867}
1868
Johan Hedberg24b78d02012-02-23 23:24:30 +02001869static bool enable_service_cache(struct hci_dev *hdev)
1870{
1871 if (!hdev_is_powered(hdev))
1872 return false;
1873
Marcel Holtmann238be782015-03-13 02:11:06 -07001874 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001875 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1876 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001877 return true;
1878 }
1879
1880 return false;
1881}
1882
Marcel Holtmann1904a852015-01-11 13:50:44 -08001883static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001884{
1885 BT_DBG("status 0x%02x", status);
1886
1887 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1888}
1889
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001890static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001891 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001892{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001893 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001894 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001895 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001896 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 -05001897 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001898 int err, found;
1899
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001900 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001901
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001902 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001903
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001904 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001905 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1906 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001907 goto unlock;
1908 }
1909
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001910 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02001911 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001912
Johan Hedberg24b78d02012-02-23 23:24:30 +02001913 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001914 err = mgmt_cmd_complete(sk, hdev->id,
1915 MGMT_OP_REMOVE_UUID,
1916 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001917 goto unlock;
1918 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001919
Johan Hedberg9246a862012-02-23 21:33:16 +02001920 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001921 }
1922
1923 found = 0;
1924
Johan Hedberg056341c2013-01-27 00:31:30 +02001925 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001926 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1927 continue;
1928
1929 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001930 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001931 found++;
1932 }
1933
1934 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001935 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1936 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001937 goto unlock;
1938 }
1939
Johan Hedberg9246a862012-02-23 21:33:16 +02001940update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001941 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001942
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001943 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001944 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001945
Johan Hedberg92da6092013-03-15 17:06:55 -05001946 err = hci_req_run(&req, remove_uuid_complete);
1947 if (err < 0) {
1948 if (err != -ENODATA)
1949 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001950
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001951 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
1952 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001953 goto unlock;
1954 }
1955
1956 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001957 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001958 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001959 goto unlock;
1960 }
1961
1962 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001963
1964unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001965 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001966 return err;
1967}
1968
Marcel Holtmann1904a852015-01-11 13:50:44 -08001969static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001970{
1971 BT_DBG("status 0x%02x", status);
1972
1973 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1974}
1975
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001976static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001977 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001978{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001979 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001980 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001981 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001982 int err;
1983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001985
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001986 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001987 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1988 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001989
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001990 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001991
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001992 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001993 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1994 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001995 goto unlock;
1996 }
1997
1998 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001999 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2000 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002001 goto unlock;
2002 }
2003
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002004 hdev->major_class = cp->major;
2005 hdev->minor_class = cp->minor;
2006
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002007 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002008 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2009 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002010 goto unlock;
2011 }
2012
Johan Hedberg890ea892013-03-15 17:06:52 -05002013 hci_req_init(&req, hdev);
2014
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002015 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002016 hci_dev_unlock(hdev);
2017 cancel_delayed_work_sync(&hdev->service_cache);
2018 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002019 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002020 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002021
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002022 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002023
Johan Hedberg92da6092013-03-15 17:06:55 -05002024 err = hci_req_run(&req, set_class_complete);
2025 if (err < 0) {
2026 if (err != -ENODATA)
2027 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002028
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002029 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2030 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002031 goto unlock;
2032 }
2033
2034 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002035 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002036 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002037 goto unlock;
2038 }
2039
2040 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002041
Johan Hedbergb5235a62012-02-21 14:32:24 +02002042unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002043 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002044 return err;
2045}
2046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002047static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002048 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002049{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002050 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002051 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2052 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002053 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002054 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002055 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002056
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002057 BT_DBG("request for %s", hdev->name);
2058
2059 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002060 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2061 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002062
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002063 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002064 if (key_count > max_key_count) {
2065 BT_ERR("load_link_keys: too big key_count value %u",
2066 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002067 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2068 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002069 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002070
Johan Hedberg86742e12011-11-07 23:13:38 +02002071 expected_len = sizeof(*cp) + key_count *
2072 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002073 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002074 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002075 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002076 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2077 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002078 }
2079
Johan Hedberg4ae14302013-01-20 14:27:13 +02002080 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002081 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2082 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002085 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002086
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002087 for (i = 0; i < key_count; i++) {
2088 struct mgmt_link_key_info *key = &cp->keys[i];
2089
Marcel Holtmann8e991132014-01-10 02:07:25 -08002090 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002091 return mgmt_cmd_status(sk, hdev->id,
2092 MGMT_OP_LOAD_LINK_KEYS,
2093 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002094 }
2095
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002096 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002097
2098 hci_link_keys_clear(hdev);
2099
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002100 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002101 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002102 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002103 changed = hci_dev_test_and_clear_flag(hdev,
2104 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002105
2106 if (changed)
2107 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002108
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002109 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002110 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002111
Johan Hedberg58e92932014-06-24 14:00:26 +03002112 /* Always ignore debug keys and require a new pairing if
2113 * the user wants to use them.
2114 */
2115 if (key->type == HCI_LK_DEBUG_COMBINATION)
2116 continue;
2117
Johan Hedberg7652ff62014-06-24 13:15:49 +03002118 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2119 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002120 }
2121
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002122 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002123
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002124 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002125
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002126 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002127}
2128
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002129static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002130 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002131{
2132 struct mgmt_ev_device_unpaired ev;
2133
2134 bacpy(&ev.addr.bdaddr, bdaddr);
2135 ev.addr.type = addr_type;
2136
2137 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002138 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002139}
2140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002141static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002142 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002143{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002144 struct mgmt_cp_unpair_device *cp = data;
2145 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002146 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002147 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002148 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002149 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002150 int err;
2151
Johan Hedberga8a1d192011-11-10 15:54:38 +02002152 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002153 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2154 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002155
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002156 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002157 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2158 MGMT_STATUS_INVALID_PARAMS,
2159 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002160
Johan Hedberg118da702013-01-20 14:27:20 +02002161 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002162 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2163 MGMT_STATUS_INVALID_PARAMS,
2164 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002165
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002166 hci_dev_lock(hdev);
2167
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002168 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002169 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2170 MGMT_STATUS_NOT_POWERED, &rp,
2171 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002172 goto unlock;
2173 }
2174
Johan Hedberge0b2b272014-02-18 17:14:31 +02002175 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002176 /* If disconnection is requested, then look up the
2177 * connection. If the remote device is connected, it
2178 * will be later used to terminate the link.
2179 *
2180 * Setting it to NULL explicitly will cause no
2181 * termination of the link.
2182 */
2183 if (cp->disconnect)
2184 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2185 &cp->addr.bdaddr);
2186 else
2187 conn = NULL;
2188
Johan Hedberg124f6e32012-02-09 13:50:12 +02002189 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002190 if (err < 0) {
2191 err = mgmt_cmd_complete(sk, hdev->id,
2192 MGMT_OP_UNPAIR_DEVICE,
2193 MGMT_STATUS_NOT_PAIRED, &rp,
2194 sizeof(rp));
2195 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002196 }
2197
Johan Hedbergec182f02015-10-21 18:03:03 +03002198 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002199 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002200
Johan Hedbergec182f02015-10-21 18:03:03 +03002201 /* LE address type */
2202 addr_type = le_addr_type(cp->addr.type);
2203
2204 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2205
2206 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002207 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002208 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2209 MGMT_STATUS_NOT_PAIRED, &rp,
2210 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002211 goto unlock;
2212 }
2213
Johan Hedbergec182f02015-10-21 18:03:03 +03002214 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2215 if (!conn) {
2216 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2217 goto done;
2218 }
2219
Johan Hedbergc81d5552015-10-22 09:38:35 +03002220 /* Abort any ongoing SMP pairing */
2221 smp_cancel_pairing(conn);
2222
Johan Hedbergec182f02015-10-21 18:03:03 +03002223 /* Defer clearing up the connection parameters until closing to
2224 * give a chance of keeping them if a repairing happens.
2225 */
2226 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2227
Johan Hedbergfc643612015-10-22 09:38:31 +03002228 /* Disable auto-connection parameters if present */
2229 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2230 if (params) {
2231 if (params->explicit_connect)
2232 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2233 else
2234 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2235 }
2236
Johan Hedbergec182f02015-10-21 18:03:03 +03002237 /* If disconnection is not requested, then clear the connection
2238 * variable so that the link is not terminated.
2239 */
2240 if (!cp->disconnect)
2241 conn = NULL;
2242
2243done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002244 /* If the connection variable is set, then termination of the
2245 * link is requested.
2246 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002247 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002248 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2249 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002250 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002251 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002252 }
2253
Johan Hedberg124f6e32012-02-09 13:50:12 +02002254 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002255 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002256 if (!cmd) {
2257 err = -ENOMEM;
2258 goto unlock;
2259 }
2260
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002261 cmd->cmd_complete = addr_cmd_complete;
2262
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002263 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002264 if (err < 0)
2265 mgmt_pending_remove(cmd);
2266
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002267unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002268 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002269 return err;
2270}
2271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002272static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002273 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002274{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002275 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002276 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002277 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002278 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002279 int err;
2280
2281 BT_DBG("");
2282
Johan Hedberg06a63b12013-01-20 14:27:21 +02002283 memset(&rp, 0, sizeof(rp));
2284 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2285 rp.addr.type = cp->addr.type;
2286
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002287 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002288 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2289 MGMT_STATUS_INVALID_PARAMS,
2290 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002291
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002292 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002293
2294 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002295 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2296 MGMT_STATUS_NOT_POWERED, &rp,
2297 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002298 goto failed;
2299 }
2300
Johan Hedberg333ae952015-03-17 13:48:47 +02002301 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002302 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2303 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002304 goto failed;
2305 }
2306
Andre Guedes591f47f2012-04-24 21:02:49 -03002307 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002308 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2309 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002310 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002311 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2312 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002313
Vishal Agarwalf9607272012-06-13 05:32:43 +05302314 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002315 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2316 MGMT_STATUS_NOT_CONNECTED, &rp,
2317 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002318 goto failed;
2319 }
2320
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002321 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002322 if (!cmd) {
2323 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002324 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002325 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002326
Johan Hedbergf5818c22014-12-05 13:36:02 +02002327 cmd->cmd_complete = generic_cmd_complete;
2328
Johan Hedberge3f2f922014-08-18 20:33:33 +03002329 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002330 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002331 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002332
2333failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002334 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002335 return err;
2336}
2337
Andre Guedes57c14772012-04-24 21:02:50 -03002338static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002339{
2340 switch (link_type) {
2341 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002342 switch (addr_type) {
2343 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002344 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002345
Johan Hedberg48264f02011-11-09 13:58:58 +02002346 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002347 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002348 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002349 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002350
Johan Hedberg4c659c32011-11-07 23:13:39 +02002351 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002352 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002353 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002354 }
2355}
2356
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002357static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2358 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002359{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002360 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002361 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002362 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002363 int err;
2364 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002365
2366 BT_DBG("");
2367
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002368 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002369
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002370 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002371 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2372 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002373 goto unlock;
2374 }
2375
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002376 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002377 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2378 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002379 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002380 }
2381
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002382 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002383 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002384 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002385 err = -ENOMEM;
2386 goto unlock;
2387 }
2388
Johan Hedberg2784eb42011-01-21 13:56:35 +02002389 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002390 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002391 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2392 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002393 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002394 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002395 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002396 continue;
2397 i++;
2398 }
2399
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002400 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002401
Johan Hedberg4c659c32011-11-07 23:13:39 +02002402 /* Recalculate length in case of filtered SCO connections, etc */
2403 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002404
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002405 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2406 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002407
Johan Hedberga38528f2011-01-22 06:46:43 +02002408 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002409
2410unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002411 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002412 return err;
2413}
2414
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002417{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002418 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002419 int err;
2420
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002421 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002422 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002423 if (!cmd)
2424 return -ENOMEM;
2425
Johan Hedbergd8457692012-02-17 14:24:57 +02002426 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002427 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002428 if (err < 0)
2429 mgmt_pending_remove(cmd);
2430
2431 return err;
2432}
2433
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002436{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002437 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002438 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002439 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002440 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002441 int err;
2442
2443 BT_DBG("");
2444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002445 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002446
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002447 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002448 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2449 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002450 goto failed;
2451 }
2452
Johan Hedbergd8457692012-02-17 14:24:57 +02002453 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002454 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002455 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2456 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002457 goto failed;
2458 }
2459
2460 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002461 struct mgmt_cp_pin_code_neg_reply ncp;
2462
2463 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002464
2465 BT_ERR("PIN code is not 16 bytes long");
2466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002468 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002469 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2470 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002471
2472 goto failed;
2473 }
2474
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002475 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002476 if (!cmd) {
2477 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002478 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002479 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002480
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002481 cmd->cmd_complete = addr_cmd_complete;
2482
Johan Hedbergd8457692012-02-17 14:24:57 +02002483 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002484 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002485 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002486
2487 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2488 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002489 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002490
2491failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002492 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002493 return err;
2494}
2495
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002496static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2497 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002498{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002499 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002500
2501 BT_DBG("");
2502
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002503 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002504 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2505 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002507 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002508
2509 hdev->io_capability = cp->io_capability;
2510
2511 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002512 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002513
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002514 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002515
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002516 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2517 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002518}
2519
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002520static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002521{
2522 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002523 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002524
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002525 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002526 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2527 continue;
2528
Johan Hedberge9a416b2011-02-19 12:05:56 -03002529 if (cmd->user_data != conn)
2530 continue;
2531
2532 return cmd;
2533 }
2534
2535 return NULL;
2536}
2537
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002538static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002539{
2540 struct mgmt_rp_pair_device rp;
2541 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002542 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002543
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002544 bacpy(&rp.addr.bdaddr, &conn->dst);
2545 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002546
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002547 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2548 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002549
2550 /* So we don't get further callbacks for this connection */
2551 conn->connect_cfm_cb = NULL;
2552 conn->security_cfm_cb = NULL;
2553 conn->disconn_cfm_cb = NULL;
2554
David Herrmann76a68ba2013-04-06 20:28:37 +02002555 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002556
2557 /* The device is paired so there is no need to remove
2558 * its connection parameters anymore.
2559 */
2560 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002561
2562 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002563
2564 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002565}
2566
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002567void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2568{
2569 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002570 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002571
2572 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002573 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002574 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002575 mgmt_pending_remove(cmd);
2576 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002577}
2578
Johan Hedberge9a416b2011-02-19 12:05:56 -03002579static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2580{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002581 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002582
2583 BT_DBG("status %u", status);
2584
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002585 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002586 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002587 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002588 return;
2589 }
2590
2591 cmd->cmd_complete(cmd, mgmt_status(status));
2592 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002593}
2594
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002595static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302596{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002597 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302598
2599 BT_DBG("status %u", status);
2600
2601 if (!status)
2602 return;
2603
2604 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002605 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302606 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002607 return;
2608 }
2609
2610 cmd->cmd_complete(cmd, mgmt_status(status));
2611 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302612}
2613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002614static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002615 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002616{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002617 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002618 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002619 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002620 u8 sec_level, auth_type;
2621 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002622 int err;
2623
2624 BT_DBG("");
2625
Szymon Jancf950a30e2013-01-18 12:48:07 +01002626 memset(&rp, 0, sizeof(rp));
2627 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2628 rp.addr.type = cp->addr.type;
2629
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002630 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002631 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2632 MGMT_STATUS_INVALID_PARAMS,
2633 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002634
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002635 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002636 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2637 MGMT_STATUS_INVALID_PARAMS,
2638 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002640 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002642 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002643 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2644 MGMT_STATUS_NOT_POWERED, &rp,
2645 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002646 goto unlock;
2647 }
2648
Johan Hedberg55e76b32015-03-10 22:34:40 +02002649 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2650 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2651 MGMT_STATUS_ALREADY_PAIRED, &rp,
2652 sizeof(rp));
2653 goto unlock;
2654 }
2655
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002656 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002657 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002658
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002659 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002660 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2661 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002662 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002663 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002664 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002665
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002666 /* When pairing a new device, it is expected to remember
2667 * this device for future connections. Adding the connection
2668 * parameter information ahead of time allows tracking
2669 * of the slave preferred values and will speed up any
2670 * further connection establishment.
2671 *
2672 * If connection parameters already exist, then they
2673 * will be kept and this function does nothing.
2674 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002675 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2676
2677 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2678 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002679
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002680 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2681 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002682 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002683 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002684
Ville Tervo30e76272011-02-22 16:10:53 -03002685 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002686 int status;
2687
2688 if (PTR_ERR(conn) == -EBUSY)
2689 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002690 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2691 status = MGMT_STATUS_NOT_SUPPORTED;
2692 else if (PTR_ERR(conn) == -ECONNREFUSED)
2693 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002694 else
2695 status = MGMT_STATUS_CONNECT_FAILED;
2696
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002697 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2698 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002699 goto unlock;
2700 }
2701
2702 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002703 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002704 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2705 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002706 goto unlock;
2707 }
2708
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002709 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002710 if (!cmd) {
2711 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002712 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002713 goto unlock;
2714 }
2715
Johan Hedberg04ab2742014-12-05 13:36:04 +02002716 cmd->cmd_complete = pairing_complete;
2717
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002718 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002719 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002720 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002721 conn->security_cfm_cb = pairing_complete_cb;
2722 conn->disconn_cfm_cb = pairing_complete_cb;
2723 } else {
2724 conn->connect_cfm_cb = le_pairing_complete_cb;
2725 conn->security_cfm_cb = le_pairing_complete_cb;
2726 conn->disconn_cfm_cb = le_pairing_complete_cb;
2727 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002728
Johan Hedberge9a416b2011-02-19 12:05:56 -03002729 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002730 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002731
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002732 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002733 hci_conn_security(conn, sec_level, auth_type, true)) {
2734 cmd->cmd_complete(cmd, 0);
2735 mgmt_pending_remove(cmd);
2736 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002737
2738 err = 0;
2739
2740unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002741 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002742 return err;
2743}
2744
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002745static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2746 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002747{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002748 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002749 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002750 struct hci_conn *conn;
2751 int err;
2752
2753 BT_DBG("");
2754
Johan Hedberg28424702012-02-02 04:02:29 +02002755 hci_dev_lock(hdev);
2756
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002757 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002758 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2759 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002760 goto unlock;
2761 }
2762
Johan Hedberg333ae952015-03-17 13:48:47 +02002763 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002764 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002765 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2766 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002767 goto unlock;
2768 }
2769
2770 conn = cmd->user_data;
2771
2772 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002773 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2774 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002775 goto unlock;
2776 }
2777
Johan Hedberga511b352014-12-11 21:45:45 +02002778 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2779 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002780
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002781 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2782 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002783unlock:
2784 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002785 return err;
2786}
2787
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002788static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002789 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002790 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002791{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002792 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002793 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002794 int err;
2795
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002796 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002797
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002798 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002799 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2800 MGMT_STATUS_NOT_POWERED, addr,
2801 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002802 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002803 }
2804
Johan Hedberg1707c602013-03-15 17:07:15 -05002805 if (addr->type == BDADDR_BREDR)
2806 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002807 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002808 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2809 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002810
Johan Hedberg272d90d2012-02-09 15:26:12 +02002811 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002812 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2813 MGMT_STATUS_NOT_CONNECTED, addr,
2814 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002815 goto done;
2816 }
2817
Johan Hedberg1707c602013-03-15 17:07:15 -05002818 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002819 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002820 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002821 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2822 MGMT_STATUS_SUCCESS, addr,
2823 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002824 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002825 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2826 MGMT_STATUS_FAILED, addr,
2827 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002828
Brian Gix47c15e22011-11-16 13:53:14 -08002829 goto done;
2830 }
2831
Johan Hedberg1707c602013-03-15 17:07:15 -05002832 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002833 if (!cmd) {
2834 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002835 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002836 }
2837
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002838 cmd->cmd_complete = addr_cmd_complete;
2839
Brian Gix0df4c182011-11-16 13:53:13 -08002840 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002841 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2842 struct hci_cp_user_passkey_reply cp;
2843
Johan Hedberg1707c602013-03-15 17:07:15 -05002844 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002845 cp.passkey = passkey;
2846 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2847 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002848 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2849 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002850
Johan Hedberga664b5b2011-02-19 12:06:02 -03002851 if (err < 0)
2852 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002853
Brian Gix0df4c182011-11-16 13:53:13 -08002854done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002855 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002856 return err;
2857}
2858
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302859static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2860 void *data, u16 len)
2861{
2862 struct mgmt_cp_pin_code_neg_reply *cp = data;
2863
2864 BT_DBG("");
2865
Johan Hedberg1707c602013-03-15 17:07:15 -05002866 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302867 MGMT_OP_PIN_CODE_NEG_REPLY,
2868 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2869}
2870
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002871static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2872 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002873{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002874 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002875
2876 BT_DBG("");
2877
2878 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002879 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2880 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002881
Johan Hedberg1707c602013-03-15 17:07:15 -05002882 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002883 MGMT_OP_USER_CONFIRM_REPLY,
2884 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002885}
2886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002887static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002888 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002889{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002890 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002891
2892 BT_DBG("");
2893
Johan Hedberg1707c602013-03-15 17:07:15 -05002894 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002895 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2896 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002897}
2898
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002899static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2900 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002901{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002902 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002903
2904 BT_DBG("");
2905
Johan Hedberg1707c602013-03-15 17:07:15 -05002906 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002907 MGMT_OP_USER_PASSKEY_REPLY,
2908 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002909}
2910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002911static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002912 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002913{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002914 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002915
2916 BT_DBG("");
2917
Johan Hedberg1707c602013-03-15 17:07:15 -05002918 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002919 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2920 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002921}
2922
Marcel Holtmann1904a852015-01-11 13:50:44 -08002923static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05002924{
2925 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002926 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05002927
2928 BT_DBG("status 0x%02x", status);
2929
2930 hci_dev_lock(hdev);
2931
Johan Hedberg333ae952015-03-17 13:48:47 +02002932 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05002933 if (!cmd)
2934 goto unlock;
2935
2936 cp = cmd->param;
2937
2938 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002939 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2940 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05002941 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002942 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2943 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05002944
2945 mgmt_pending_remove(cmd);
2946
2947unlock:
2948 hci_dev_unlock(hdev);
2949}
2950
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002951static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002952 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002953{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002954 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002955 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002956 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002957 int err;
2958
2959 BT_DBG("");
2960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002961 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002962
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002963 /* If the old values are the same as the new ones just return a
2964 * direct command complete event.
2965 */
2966 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2967 !memcmp(hdev->short_name, cp->short_name,
2968 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002969 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2970 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002971 goto failed;
2972 }
2973
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002974 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002975
Johan Hedbergb5235a62012-02-21 14:32:24 +02002976 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002977 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002978
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002979 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2980 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002981 if (err < 0)
2982 goto failed;
2983
Marcel Holtmannf6b77122015-03-14 19:28:05 -07002984 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
2985 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002986
Johan Hedbergb5235a62012-02-21 14:32:24 +02002987 goto failed;
2988 }
2989
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002990 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002991 if (!cmd) {
2992 err = -ENOMEM;
2993 goto failed;
2994 }
2995
Johan Hedberg13928972013-03-15 17:07:00 -05002996 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2997
Johan Hedberg890ea892013-03-15 17:06:52 -05002998 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002999
3000 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003001 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003002 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003003 }
3004
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003005 /* The name is stored in the scan response data and so
3006 * no need to udpate the advertising data here.
3007 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003008 if (lmp_le_capable(hdev))
Johan Hedbergf2252572015-11-18 12:49:20 +02003009 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Johan Hedberg3f985052013-03-15 17:07:02 -05003010
Johan Hedberg13928972013-03-15 17:07:00 -05003011 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003012 if (err < 0)
3013 mgmt_pending_remove(cmd);
3014
3015failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003016 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003017 return err;
3018}
3019
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003020static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3021 u16 opcode, struct sk_buff *skb)
3022{
3023 struct mgmt_rp_read_local_oob_data mgmt_rp;
3024 size_t rp_size = sizeof(mgmt_rp);
3025 struct mgmt_pending_cmd *cmd;
3026
3027 BT_DBG("%s status %u", hdev->name, status);
3028
3029 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3030 if (!cmd)
3031 return;
3032
3033 if (status || !skb) {
3034 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3035 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3036 goto remove;
3037 }
3038
3039 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3040
3041 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3042 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3043
3044 if (skb->len < sizeof(*rp)) {
3045 mgmt_cmd_status(cmd->sk, hdev->id,
3046 MGMT_OP_READ_LOCAL_OOB_DATA,
3047 MGMT_STATUS_FAILED);
3048 goto remove;
3049 }
3050
3051 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3052 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3053
3054 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3055 } else {
3056 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3057
3058 if (skb->len < sizeof(*rp)) {
3059 mgmt_cmd_status(cmd->sk, hdev->id,
3060 MGMT_OP_READ_LOCAL_OOB_DATA,
3061 MGMT_STATUS_FAILED);
3062 goto remove;
3063 }
3064
3065 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3066 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3067
3068 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3069 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3070 }
3071
3072 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3073 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3074
3075remove:
3076 mgmt_pending_remove(cmd);
3077}
3078
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003079static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003080 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003081{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003082 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003083 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003084 int err;
3085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003087
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003088 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003089
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003090 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003091 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3092 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003093 goto unlock;
3094 }
3095
Andre Guedes9a1a1992012-07-24 15:03:48 -03003096 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003097 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3098 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003099 goto unlock;
3100 }
3101
Johan Hedberg333ae952015-03-17 13:48:47 +02003102 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003103 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3104 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003105 goto unlock;
3106 }
3107
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003108 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003109 if (!cmd) {
3110 err = -ENOMEM;
3111 goto unlock;
3112 }
3113
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003114 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003115
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003116 if (bredr_sc_enabled(hdev))
3117 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3118 else
3119 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3120
3121 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003122 if (err < 0)
3123 mgmt_pending_remove(cmd);
3124
3125unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003126 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003127 return err;
3128}
3129
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003130static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003132{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003133 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003134 int err;
3135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003136 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003137
Johan Hedberg5d57e792015-01-23 10:10:38 +02003138 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003139 return mgmt_cmd_complete(sk, hdev->id,
3140 MGMT_OP_ADD_REMOTE_OOB_DATA,
3141 MGMT_STATUS_INVALID_PARAMS,
3142 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003144 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003145
Marcel Holtmannec109112014-01-10 02:07:30 -08003146 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3147 struct mgmt_cp_add_remote_oob_data *cp = data;
3148 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003149
Johan Hedbergc19a4952014-11-17 20:52:19 +02003150 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003151 err = mgmt_cmd_complete(sk, hdev->id,
3152 MGMT_OP_ADD_REMOTE_OOB_DATA,
3153 MGMT_STATUS_INVALID_PARAMS,
3154 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003155 goto unlock;
3156 }
3157
Marcel Holtmannec109112014-01-10 02:07:30 -08003158 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003159 cp->addr.type, cp->hash,
3160 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003161 if (err < 0)
3162 status = MGMT_STATUS_FAILED;
3163 else
3164 status = MGMT_STATUS_SUCCESS;
3165
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003166 err = mgmt_cmd_complete(sk, hdev->id,
3167 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3168 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003169 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3170 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003171 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003172 u8 status;
3173
Johan Hedberg86df9202014-10-26 20:52:27 +01003174 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003175 /* Enforce zero-valued 192-bit parameters as
3176 * long as legacy SMP OOB isn't implemented.
3177 */
3178 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3179 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003180 err = mgmt_cmd_complete(sk, hdev->id,
3181 MGMT_OP_ADD_REMOTE_OOB_DATA,
3182 MGMT_STATUS_INVALID_PARAMS,
3183 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003184 goto unlock;
3185 }
3186
Johan Hedberg86df9202014-10-26 20:52:27 +01003187 rand192 = NULL;
3188 hash192 = NULL;
3189 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003190 /* In case one of the P-192 values is set to zero,
3191 * then just disable OOB data for P-192.
3192 */
3193 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3194 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3195 rand192 = NULL;
3196 hash192 = NULL;
3197 } else {
3198 rand192 = cp->rand192;
3199 hash192 = cp->hash192;
3200 }
3201 }
3202
3203 /* In case one of the P-256 values is set to zero, then just
3204 * disable OOB data for P-256.
3205 */
3206 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3207 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3208 rand256 = NULL;
3209 hash256 = NULL;
3210 } else {
3211 rand256 = cp->rand256;
3212 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003213 }
3214
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003215 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003216 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003217 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003218 if (err < 0)
3219 status = MGMT_STATUS_FAILED;
3220 else
3221 status = MGMT_STATUS_SUCCESS;
3222
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003223 err = mgmt_cmd_complete(sk, hdev->id,
3224 MGMT_OP_ADD_REMOTE_OOB_DATA,
3225 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003226 } else {
3227 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003228 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3229 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003230 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003231
Johan Hedbergc19a4952014-11-17 20:52:19 +02003232unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003233 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003234 return err;
3235}
3236
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003237static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003238 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003239{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003240 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003241 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003242 int err;
3243
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003244 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003245
Johan Hedbergc19a4952014-11-17 20:52:19 +02003246 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003247 return mgmt_cmd_complete(sk, hdev->id,
3248 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3249 MGMT_STATUS_INVALID_PARAMS,
3250 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003252 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003253
Johan Hedbergeedbd582014-11-15 09:34:23 +02003254 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3255 hci_remote_oob_data_clear(hdev);
3256 status = MGMT_STATUS_SUCCESS;
3257 goto done;
3258 }
3259
Johan Hedberg6928a922014-10-26 20:46:09 +01003260 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003261 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003262 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003263 else
Szymon Janca6785be2012-12-13 15:11:21 +01003264 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003265
Johan Hedbergeedbd582014-11-15 09:34:23 +02003266done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003267 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3268 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003269
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003270 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003271 return err;
3272}
3273
Johan Hedberge68f0722015-11-11 08:30:30 +02003274void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003275{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003276 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003277
Andre Guedes7c307722013-04-30 15:29:28 -03003278 BT_DBG("status %d", status);
3279
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003280 hci_dev_lock(hdev);
3281
Johan Hedberg333ae952015-03-17 13:48:47 +02003282 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003283 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003284 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003285
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003286 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003287 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003288 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003289 }
3290
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003291 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003292}
3293
Johan Hedberg591752a2015-11-11 08:11:24 +02003294static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3295 uint8_t *mgmt_status)
3296{
3297 switch (type) {
3298 case DISCOV_TYPE_LE:
3299 *mgmt_status = mgmt_le_support(hdev);
3300 if (*mgmt_status)
3301 return false;
3302 break;
3303 case DISCOV_TYPE_INTERLEAVED:
3304 *mgmt_status = mgmt_le_support(hdev);
3305 if (*mgmt_status)
3306 return false;
3307 /* Intentional fall-through */
3308 case DISCOV_TYPE_BREDR:
3309 *mgmt_status = mgmt_bredr_support(hdev);
3310 if (*mgmt_status)
3311 return false;
3312 break;
3313 default:
3314 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3315 return false;
3316 }
3317
3318 return true;
3319}
3320
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003321static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003322 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003323{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003324 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003325 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003326 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003327 int err;
3328
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003329 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003330
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003331 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003332
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003333 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003334 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3335 MGMT_STATUS_NOT_POWERED,
3336 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003337 goto failed;
3338 }
3339
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003340 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003341 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003342 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3343 MGMT_STATUS_BUSY, &cp->type,
3344 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003345 goto failed;
3346 }
3347
Johan Hedberg591752a2015-11-11 08:11:24 +02003348 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3349 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3350 status, &cp->type, sizeof(cp->type));
3351 goto failed;
3352 }
3353
Marcel Holtmann22078802014-12-05 11:45:22 +01003354 /* Clear the discovery filter first to free any previously
3355 * allocated memory for the UUID list.
3356 */
3357 hci_discovery_filter_clear(hdev);
3358
Andre Guedes4aab14e2012-02-17 20:39:36 -03003359 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003360 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003361
Johan Hedberge68f0722015-11-11 08:30:30 +02003362 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
3363 if (!cmd) {
3364 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003365 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003366 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003367
Johan Hedberge68f0722015-11-11 08:30:30 +02003368 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003369
3370 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003371 queue_work(hdev->req_workqueue, &hdev->discov_update);
3372 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003373
3374failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003375 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003376 return err;
3377}
3378
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003379static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3380 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003381{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003382 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3383 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003384}
3385
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003386static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3387 void *data, u16 len)
3388{
3389 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003390 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003391 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3392 u16 uuid_count, expected_len;
3393 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003394 int err;
3395
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003396 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003397
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003398 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003399
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003400 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003401 err = mgmt_cmd_complete(sk, hdev->id,
3402 MGMT_OP_START_SERVICE_DISCOVERY,
3403 MGMT_STATUS_NOT_POWERED,
3404 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003405 goto failed;
3406 }
3407
3408 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003409 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003410 err = mgmt_cmd_complete(sk, hdev->id,
3411 MGMT_OP_START_SERVICE_DISCOVERY,
3412 MGMT_STATUS_BUSY, &cp->type,
3413 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003414 goto failed;
3415 }
3416
3417 uuid_count = __le16_to_cpu(cp->uuid_count);
3418 if (uuid_count > max_uuid_count) {
3419 BT_ERR("service_discovery: too big uuid_count value %u",
3420 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003421 err = mgmt_cmd_complete(sk, hdev->id,
3422 MGMT_OP_START_SERVICE_DISCOVERY,
3423 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3424 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003425 goto failed;
3426 }
3427
3428 expected_len = sizeof(*cp) + uuid_count * 16;
3429 if (expected_len != len) {
3430 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3431 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003432 err = mgmt_cmd_complete(sk, hdev->id,
3433 MGMT_OP_START_SERVICE_DISCOVERY,
3434 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3435 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003436 goto failed;
3437 }
3438
Johan Hedberg591752a2015-11-11 08:11:24 +02003439 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3440 err = mgmt_cmd_complete(sk, hdev->id,
3441 MGMT_OP_START_SERVICE_DISCOVERY,
3442 status, &cp->type, sizeof(cp->type));
3443 goto failed;
3444 }
3445
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003446 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003447 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003448 if (!cmd) {
3449 err = -ENOMEM;
3450 goto failed;
3451 }
3452
Johan Hedberg2922a942014-12-05 13:36:06 +02003453 cmd->cmd_complete = service_discovery_cmd_complete;
3454
Marcel Holtmann22078802014-12-05 11:45:22 +01003455 /* Clear the discovery filter first to free any previously
3456 * allocated memory for the UUID list.
3457 */
3458 hci_discovery_filter_clear(hdev);
3459
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003460 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003461 hdev->discovery.type = cp->type;
3462 hdev->discovery.rssi = cp->rssi;
3463 hdev->discovery.uuid_count = uuid_count;
3464
3465 if (uuid_count > 0) {
3466 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3467 GFP_KERNEL);
3468 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003469 err = mgmt_cmd_complete(sk, hdev->id,
3470 MGMT_OP_START_SERVICE_DISCOVERY,
3471 MGMT_STATUS_FAILED,
3472 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003473 mgmt_pending_remove(cmd);
3474 goto failed;
3475 }
3476 }
3477
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003478 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003479 queue_work(hdev->req_workqueue, &hdev->discov_update);
3480 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003481
3482failed:
3483 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003484 return err;
3485}
3486
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003487void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003488{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003489 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003490
Andre Guedes0e05bba2013-04-30 15:29:33 -03003491 BT_DBG("status %d", status);
3492
3493 hci_dev_lock(hdev);
3494
Johan Hedberg333ae952015-03-17 13:48:47 +02003495 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003496 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003497 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003498 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003499 }
3500
Andre Guedes0e05bba2013-04-30 15:29:33 -03003501 hci_dev_unlock(hdev);
3502}
3503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003504static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003505 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003506{
Johan Hedbergd9306502012-02-20 23:25:18 +02003507 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003508 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003509 int err;
3510
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003511 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003512
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003513 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003514
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003515 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003516 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3517 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3518 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003519 goto unlock;
3520 }
3521
3522 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003523 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3524 MGMT_STATUS_INVALID_PARAMS,
3525 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003526 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003527 }
3528
Johan Hedberg2922a942014-12-05 13:36:06 +02003529 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003530 if (!cmd) {
3531 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003532 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003533 }
3534
Johan Hedberg2922a942014-12-05 13:36:06 +02003535 cmd->cmd_complete = generic_cmd_complete;
3536
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003537 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3538 queue_work(hdev->req_workqueue, &hdev->discov_update);
3539 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003540
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003541unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003542 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003543 return err;
3544}
3545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003546static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003547 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003548{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003549 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003550 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003551 int err;
3552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003553 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003554
Johan Hedberg561aafb2012-01-04 13:31:59 +02003555 hci_dev_lock(hdev);
3556
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003557 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003558 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3559 MGMT_STATUS_FAILED, &cp->addr,
3560 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003561 goto failed;
3562 }
3563
Johan Hedberga198e7b2012-02-17 14:27:06 +02003564 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003565 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003566 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3567 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3568 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003569 goto failed;
3570 }
3571
3572 if (cp->name_known) {
3573 e->name_state = NAME_KNOWN;
3574 list_del(&e->list);
3575 } else {
3576 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003577 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003578 }
3579
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003580 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3581 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003582
3583failed:
3584 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003585 return err;
3586}
3587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003588static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003589 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003590{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003591 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003592 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003593 int err;
3594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003595 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003596
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003597 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003598 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3599 MGMT_STATUS_INVALID_PARAMS,
3600 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003601
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003602 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003603
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003604 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3605 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003606 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003607 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003608 goto done;
3609 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003610
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003611 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3612 sk);
3613 status = MGMT_STATUS_SUCCESS;
3614
3615done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003616 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3617 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003619 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003620
3621 return err;
3622}
3623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003624static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003625 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003626{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003627 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003628 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003629 int err;
3630
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003631 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003632
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003633 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003634 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3635 MGMT_STATUS_INVALID_PARAMS,
3636 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003638 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003639
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003640 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3641 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003642 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003643 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003644 goto done;
3645 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003646
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003647 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3648 sk);
3649 status = MGMT_STATUS_SUCCESS;
3650
3651done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003652 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3653 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003655 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003656
3657 return err;
3658}
3659
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003660static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3661 u16 len)
3662{
3663 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003664 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003665 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003666 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003667
3668 BT_DBG("%s", hdev->name);
3669
Szymon Jancc72d4b82012-03-16 16:02:57 +01003670 source = __le16_to_cpu(cp->source);
3671
3672 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003673 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3674 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003675
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003676 hci_dev_lock(hdev);
3677
Szymon Jancc72d4b82012-03-16 16:02:57 +01003678 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003679 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3680 hdev->devid_product = __le16_to_cpu(cp->product);
3681 hdev->devid_version = __le16_to_cpu(cp->version);
3682
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003683 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3684 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003685
Johan Hedberg890ea892013-03-15 17:06:52 -05003686 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003687 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003688 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003689
3690 hci_dev_unlock(hdev);
3691
3692 return err;
3693}
3694
Arman Uguray24b4f382015-03-23 15:57:12 -07003695static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3696 u16 opcode)
3697{
3698 BT_DBG("status %d", status);
3699}
3700
Marcel Holtmann1904a852015-01-11 13:50:44 -08003701static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3702 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003703{
3704 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003705 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003706 u8 instance;
3707 struct adv_info *adv_instance;
3708 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003709
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303710 hci_dev_lock(hdev);
3711
Johan Hedberg4375f102013-09-25 13:26:10 +03003712 if (status) {
3713 u8 mgmt_err = mgmt_status(status);
3714
3715 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3716 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303717 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003718 }
3719
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003720 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003721 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003722 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003723 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003724
Johan Hedberg4375f102013-09-25 13:26:10 +03003725 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3726 &match);
3727
3728 new_settings(hdev, match.sk);
3729
3730 if (match.sk)
3731 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303732
Arman Uguray24b4f382015-03-23 15:57:12 -07003733 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003734 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003735 */
3736 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003737 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
3738 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003739 goto unlock;
3740
Florian Grandel7816b822015-06-18 03:16:45 +02003741 instance = hdev->cur_adv_instance;
3742 if (!instance) {
3743 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3744 struct adv_info, list);
3745 if (!adv_instance)
3746 goto unlock;
3747
3748 instance = adv_instance->instance;
3749 }
3750
Arman Uguray24b4f382015-03-23 15:57:12 -07003751 hci_req_init(&req, hdev);
3752
Johan Hedbergf2252572015-11-18 12:49:20 +02003753 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003754
Florian Grandel7816b822015-06-18 03:16:45 +02003755 if (!err)
3756 err = hci_req_run(&req, enable_advertising_instance);
3757
3758 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003759 BT_ERR("Failed to re-configure advertising");
3760
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303761unlock:
3762 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003763}
3764
Marcel Holtmann21b51872013-10-10 09:47:53 -07003765static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3766 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003767{
3768 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003769 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003770 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003771 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003772 int err;
3773
3774 BT_DBG("request for %s", hdev->name);
3775
Johan Hedberge6fe7982013-10-02 15:45:22 +03003776 status = mgmt_le_support(hdev);
3777 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003778 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3779 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003780
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003781 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003782 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3783 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003784
3785 hci_dev_lock(hdev);
3786
3787 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003788
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003789 /* The following conditions are ones which mean that we should
3790 * not do any HCI communication but directly send a mgmt
3791 * response to user space (after toggling the flag if
3792 * necessary).
3793 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003794 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003795 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3796 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003797 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003798 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003799 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003800 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003801
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003802 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07003803 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003804 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003805 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003806 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003807 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003808 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003809 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003810 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003811 }
3812
3813 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3814 if (err < 0)
3815 goto unlock;
3816
3817 if (changed)
3818 err = new_settings(hdev, sk);
3819
3820 goto unlock;
3821 }
3822
Johan Hedberg333ae952015-03-17 13:48:47 +02003823 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3824 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003825 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3826 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03003827 goto unlock;
3828 }
3829
3830 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3831 if (!cmd) {
3832 err = -ENOMEM;
3833 goto unlock;
3834 }
3835
3836 hci_req_init(&req, hdev);
3837
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003838 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003839 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003840 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003841 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003842
Florian Grandel7816b822015-06-18 03:16:45 +02003843 cancel_adv_timeout(hdev);
3844
Arman Uguray24b4f382015-03-23 15:57:12 -07003845 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02003846 /* Switch to instance "0" for the Set Advertising setting.
3847 * We cannot use update_[adv|scan_rsp]_data() here as the
3848 * HCI_ADVERTISING flag is not yet set.
3849 */
Johan Hedbergf2252572015-11-18 12:49:20 +02003850 __hci_req_update_adv_data(&req, 0x00);
3851 __hci_req_update_scan_rsp_data(&req, 0x00);
3852 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003853 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02003854 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003855 }
Johan Hedberg4375f102013-09-25 13:26:10 +03003856
3857 err = hci_req_run(&req, set_advertising_complete);
3858 if (err < 0)
3859 mgmt_pending_remove(cmd);
3860
3861unlock:
3862 hci_dev_unlock(hdev);
3863 return err;
3864}
3865
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003866static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3867 void *data, u16 len)
3868{
3869 struct mgmt_cp_set_static_address *cp = data;
3870 int err;
3871
3872 BT_DBG("%s", hdev->name);
3873
Marcel Holtmann62af4442013-10-02 22:10:32 -07003874 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003875 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3876 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003877
3878 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003879 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3880 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003881
3882 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3883 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02003884 return mgmt_cmd_status(sk, hdev->id,
3885 MGMT_OP_SET_STATIC_ADDRESS,
3886 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003887
3888 /* Two most significant bits shall be set */
3889 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003890 return mgmt_cmd_status(sk, hdev->id,
3891 MGMT_OP_SET_STATIC_ADDRESS,
3892 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003893 }
3894
3895 hci_dev_lock(hdev);
3896
3897 bacpy(&hdev->static_addr, &cp->bdaddr);
3898
Marcel Holtmann93690c22015-03-06 10:11:21 -08003899 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
3900 if (err < 0)
3901 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003902
Marcel Holtmann93690c22015-03-06 10:11:21 -08003903 err = new_settings(hdev, sk);
3904
3905unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003906 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003907 return err;
3908}
3909
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003910static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3911 void *data, u16 len)
3912{
3913 struct mgmt_cp_set_scan_params *cp = data;
3914 __u16 interval, window;
3915 int err;
3916
3917 BT_DBG("%s", hdev->name);
3918
3919 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003920 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3921 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003922
3923 interval = __le16_to_cpu(cp->interval);
3924
3925 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003926 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3927 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003928
3929 window = __le16_to_cpu(cp->window);
3930
3931 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003932 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3933 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003934
Marcel Holtmann899e1072013-10-14 09:55:32 -07003935 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02003936 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3937 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07003938
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003939 hci_dev_lock(hdev);
3940
3941 hdev->le_scan_interval = interval;
3942 hdev->le_scan_window = window;
3943
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003944 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
3945 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003946
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003947 /* If background scan is running, restart it so new parameters are
3948 * loaded.
3949 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003950 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003951 hdev->discovery.state == DISCOVERY_STOPPED) {
3952 struct hci_request req;
3953
3954 hci_req_init(&req, hdev);
3955
3956 hci_req_add_le_scan_disable(&req);
3957 hci_req_add_le_passive_scan(&req);
3958
3959 hci_req_run(&req, NULL);
3960 }
3961
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003962 hci_dev_unlock(hdev);
3963
3964 return err;
3965}
3966
Marcel Holtmann1904a852015-01-11 13:50:44 -08003967static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
3968 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05003969{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003970 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003971
3972 BT_DBG("status 0x%02x", status);
3973
3974 hci_dev_lock(hdev);
3975
Johan Hedberg333ae952015-03-17 13:48:47 +02003976 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003977 if (!cmd)
3978 goto unlock;
3979
3980 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003981 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3982 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05003983 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003984 struct mgmt_mode *cp = cmd->param;
3985
3986 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003987 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003988 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003989 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003990
Johan Hedberg33e38b32013-03-15 17:07:05 -05003991 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3992 new_settings(hdev, cmd->sk);
3993 }
3994
3995 mgmt_pending_remove(cmd);
3996
3997unlock:
3998 hci_dev_unlock(hdev);
3999}
4000
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004001static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004002 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004003{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004004 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004005 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004006 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004007 int err;
4008
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004009 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004010
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004011 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004012 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004013 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4014 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004015
Johan Hedberga7e80f22013-01-09 16:05:19 +02004016 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004017 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4018 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004019
Antti Julkuf6422ec2011-06-22 13:11:56 +03004020 hci_dev_lock(hdev);
4021
Johan Hedberg333ae952015-03-17 13:48:47 +02004022 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004023 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4024 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004025 goto unlock;
4026 }
4027
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004028 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004029 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4030 hdev);
4031 goto unlock;
4032 }
4033
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004034 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004035 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004036 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4037 hdev);
4038 new_settings(hdev, sk);
4039 goto unlock;
4040 }
4041
Johan Hedberg33e38b32013-03-15 17:07:05 -05004042 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4043 data, len);
4044 if (!cmd) {
4045 err = -ENOMEM;
4046 goto unlock;
4047 }
4048
4049 hci_req_init(&req, hdev);
4050
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004051 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004052
4053 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004054 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004055 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4056 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004057 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004058 }
4059
Johan Hedberg33e38b32013-03-15 17:07:05 -05004060unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004061 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004062
Antti Julkuf6422ec2011-06-22 13:11:56 +03004063 return err;
4064}
4065
Marcel Holtmann1904a852015-01-11 13:50:44 -08004066static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004067{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004068 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004069
4070 BT_DBG("status 0x%02x", status);
4071
4072 hci_dev_lock(hdev);
4073
Johan Hedberg333ae952015-03-17 13:48:47 +02004074 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004075 if (!cmd)
4076 goto unlock;
4077
4078 if (status) {
4079 u8 mgmt_err = mgmt_status(status);
4080
4081 /* We need to restore the flag if related HCI commands
4082 * failed.
4083 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004084 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004085
Johan Hedberga69e8372015-03-06 21:08:53 +02004086 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004087 } else {
4088 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4089 new_settings(hdev, cmd->sk);
4090 }
4091
4092 mgmt_pending_remove(cmd);
4093
4094unlock:
4095 hci_dev_unlock(hdev);
4096}
4097
4098static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4099{
4100 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004101 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004102 struct hci_request req;
4103 int err;
4104
4105 BT_DBG("request for %s", hdev->name);
4106
4107 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004108 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4109 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004110
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004111 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004112 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4113 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004114
4115 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004116 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4117 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004118
4119 hci_dev_lock(hdev);
4120
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004121 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004122 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4123 goto unlock;
4124 }
4125
4126 if (!hdev_is_powered(hdev)) {
4127 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004128 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4129 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4130 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4131 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4132 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004133 }
4134
Marcel Holtmannce05d602015-03-13 02:11:03 -07004135 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004136
4137 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4138 if (err < 0)
4139 goto unlock;
4140
4141 err = new_settings(hdev, sk);
4142 goto unlock;
4143 }
4144
4145 /* Reject disabling when powered on */
4146 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004147 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4148 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004149 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004150 } else {
4151 /* When configuring a dual-mode controller to operate
4152 * with LE only and using a static address, then switching
4153 * BR/EDR back on is not allowed.
4154 *
4155 * Dual-mode controllers shall operate with the public
4156 * address as its identity address for BR/EDR and LE. So
4157 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004158 *
4159 * The same restrictions applies when secure connections
4160 * has been enabled. For BR/EDR this is a controller feature
4161 * while for LE it is a host stack feature. This means that
4162 * switching BR/EDR back on when secure connections has been
4163 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004164 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004165 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004166 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004167 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004168 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4169 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004170 goto unlock;
4171 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004172 }
4173
Johan Hedberg333ae952015-03-17 13:48:47 +02004174 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004175 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4176 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004177 goto unlock;
4178 }
4179
4180 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4181 if (!cmd) {
4182 err = -ENOMEM;
4183 goto unlock;
4184 }
4185
Johan Hedbergf2252572015-11-18 12:49:20 +02004186 /* We need to flip the bit already here so that
4187 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004188 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004189 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004190
4191 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004192
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004193 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004194 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004195
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004196 /* Since only the advertising data flags will change, there
4197 * is no need to update the scan response data.
4198 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004199 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004200
Johan Hedberg0663ca22013-10-02 13:43:14 +03004201 err = hci_req_run(&req, set_bredr_complete);
4202 if (err < 0)
4203 mgmt_pending_remove(cmd);
4204
4205unlock:
4206 hci_dev_unlock(hdev);
4207 return err;
4208}
4209
Johan Hedberga1443f52015-01-23 15:42:46 +02004210static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4211{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004212 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004213 struct mgmt_mode *cp;
4214
4215 BT_DBG("%s status %u", hdev->name, status);
4216
4217 hci_dev_lock(hdev);
4218
Johan Hedberg333ae952015-03-17 13:48:47 +02004219 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004220 if (!cmd)
4221 goto unlock;
4222
4223 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004224 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4225 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004226 goto remove;
4227 }
4228
4229 cp = cmd->param;
4230
4231 switch (cp->val) {
4232 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004233 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4234 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004235 break;
4236 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004237 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004238 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004239 break;
4240 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004241 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4242 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004243 break;
4244 }
4245
4246 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4247 new_settings(hdev, cmd->sk);
4248
4249remove:
4250 mgmt_pending_remove(cmd);
4251unlock:
4252 hci_dev_unlock(hdev);
4253}
4254
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004255static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4256 void *data, u16 len)
4257{
4258 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004259 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004260 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004261 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004262 int err;
4263
4264 BT_DBG("request for %s", hdev->name);
4265
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004266 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004267 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004268 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4269 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004270
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004271 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004272 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004273 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004274 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4275 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004276
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004277 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004278 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004279 MGMT_STATUS_INVALID_PARAMS);
4280
4281 hci_dev_lock(hdev);
4282
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004283 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004284 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004285 bool changed;
4286
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004287 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004288 changed = !hci_dev_test_and_set_flag(hdev,
4289 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004290 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004291 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004292 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004293 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004294 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004295 changed = hci_dev_test_and_clear_flag(hdev,
4296 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004297 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004298 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004299
4300 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4301 if (err < 0)
4302 goto failed;
4303
4304 if (changed)
4305 err = new_settings(hdev, sk);
4306
4307 goto failed;
4308 }
4309
Johan Hedberg333ae952015-03-17 13:48:47 +02004310 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004311 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4312 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004313 goto failed;
4314 }
4315
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004316 val = !!cp->val;
4317
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004318 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4319 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004320 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4321 goto failed;
4322 }
4323
4324 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4325 if (!cmd) {
4326 err = -ENOMEM;
4327 goto failed;
4328 }
4329
Johan Hedberga1443f52015-01-23 15:42:46 +02004330 hci_req_init(&req, hdev);
4331 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4332 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004333 if (err < 0) {
4334 mgmt_pending_remove(cmd);
4335 goto failed;
4336 }
4337
4338failed:
4339 hci_dev_unlock(hdev);
4340 return err;
4341}
4342
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004343static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4344 void *data, u16 len)
4345{
4346 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004347 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004348 int err;
4349
4350 BT_DBG("request for %s", hdev->name);
4351
Johan Hedbergb97109792014-06-24 14:00:28 +03004352 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004353 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4354 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004355
4356 hci_dev_lock(hdev);
4357
4358 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004359 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004360 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004361 changed = hci_dev_test_and_clear_flag(hdev,
4362 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004363
Johan Hedbergb97109792014-06-24 14:00:28 +03004364 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004365 use_changed = !hci_dev_test_and_set_flag(hdev,
4366 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004367 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004368 use_changed = hci_dev_test_and_clear_flag(hdev,
4369 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004370
4371 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004372 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004373 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4374 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4375 sizeof(mode), &mode);
4376 }
4377
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004378 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4379 if (err < 0)
4380 goto unlock;
4381
4382 if (changed)
4383 err = new_settings(hdev, sk);
4384
4385unlock:
4386 hci_dev_unlock(hdev);
4387 return err;
4388}
4389
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004390static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4391 u16 len)
4392{
4393 struct mgmt_cp_set_privacy *cp = cp_data;
4394 bool changed;
4395 int err;
4396
4397 BT_DBG("request for %s", hdev->name);
4398
4399 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004400 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4401 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004402
4403 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004404 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4405 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004406
4407 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004408 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4409 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004410
4411 hci_dev_lock(hdev);
4412
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004413 /* If user space supports this command it is also expected to
4414 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4415 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004416 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004417
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004418 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004419 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004420 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004421 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004422 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004423 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004424 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004425 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004426 }
4427
4428 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4429 if (err < 0)
4430 goto unlock;
4431
4432 if (changed)
4433 err = new_settings(hdev, sk);
4434
4435unlock:
4436 hci_dev_unlock(hdev);
4437 return err;
4438}
4439
Johan Hedberg41edf162014-02-18 10:19:35 +02004440static bool irk_is_valid(struct mgmt_irk_info *irk)
4441{
4442 switch (irk->addr.type) {
4443 case BDADDR_LE_PUBLIC:
4444 return true;
4445
4446 case BDADDR_LE_RANDOM:
4447 /* Two most significant bits shall be set */
4448 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4449 return false;
4450 return true;
4451 }
4452
4453 return false;
4454}
4455
4456static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4457 u16 len)
4458{
4459 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004460 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4461 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004462 u16 irk_count, expected_len;
4463 int i, err;
4464
4465 BT_DBG("request for %s", hdev->name);
4466
4467 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004468 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4469 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004470
4471 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004472 if (irk_count > max_irk_count) {
4473 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004474 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4475 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004476 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004477
4478 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4479 if (expected_len != len) {
4480 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004481 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004482 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4483 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004484 }
4485
4486 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4487
4488 for (i = 0; i < irk_count; i++) {
4489 struct mgmt_irk_info *key = &cp->irks[i];
4490
4491 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004492 return mgmt_cmd_status(sk, hdev->id,
4493 MGMT_OP_LOAD_IRKS,
4494 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004495 }
4496
4497 hci_dev_lock(hdev);
4498
4499 hci_smp_irks_clear(hdev);
4500
4501 for (i = 0; i < irk_count; i++) {
4502 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004503
Johan Hedberg85813a72015-10-21 18:02:59 +03004504 hci_add_irk(hdev, &irk->addr.bdaddr,
4505 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004506 BDADDR_ANY);
4507 }
4508
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004509 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004510
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004511 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004512
4513 hci_dev_unlock(hdev);
4514
4515 return err;
4516}
4517
Johan Hedberg3f706b72013-01-20 14:27:16 +02004518static bool ltk_is_valid(struct mgmt_ltk_info *key)
4519{
4520 if (key->master != 0x00 && key->master != 0x01)
4521 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004522
4523 switch (key->addr.type) {
4524 case BDADDR_LE_PUBLIC:
4525 return true;
4526
4527 case BDADDR_LE_RANDOM:
4528 /* Two most significant bits shall be set */
4529 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4530 return false;
4531 return true;
4532 }
4533
4534 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004535}
4536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004537static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004538 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004539{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004540 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004541 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4542 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004543 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004544 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004545
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004546 BT_DBG("request for %s", hdev->name);
4547
4548 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004549 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4550 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004551
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004552 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004553 if (key_count > max_key_count) {
4554 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004555 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4556 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004557 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004558
4559 expected_len = sizeof(*cp) + key_count *
4560 sizeof(struct mgmt_ltk_info);
4561 if (expected_len != len) {
4562 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004563 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004564 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4565 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004566 }
4567
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004568 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004569
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004570 for (i = 0; i < key_count; i++) {
4571 struct mgmt_ltk_info *key = &cp->keys[i];
4572
Johan Hedberg3f706b72013-01-20 14:27:16 +02004573 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004574 return mgmt_cmd_status(sk, hdev->id,
4575 MGMT_OP_LOAD_LONG_TERM_KEYS,
4576 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004577 }
4578
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004579 hci_dev_lock(hdev);
4580
4581 hci_smp_ltks_clear(hdev);
4582
4583 for (i = 0; i < key_count; i++) {
4584 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004585 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004586
Johan Hedberg61b43352014-05-29 19:36:53 +03004587 switch (key->type) {
4588 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004589 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004590 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004591 break;
4592 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004593 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004594 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004595 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004596 case MGMT_LTK_P256_UNAUTH:
4597 authenticated = 0x00;
4598 type = SMP_LTK_P256;
4599 break;
4600 case MGMT_LTK_P256_AUTH:
4601 authenticated = 0x01;
4602 type = SMP_LTK_P256;
4603 break;
4604 case MGMT_LTK_P256_DEBUG:
4605 authenticated = 0x00;
4606 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004607 default:
4608 continue;
4609 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004610
Johan Hedberg85813a72015-10-21 18:02:59 +03004611 hci_add_ltk(hdev, &key->addr.bdaddr,
4612 le_addr_type(key->addr.type), type, authenticated,
4613 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004614 }
4615
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004616 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004617 NULL, 0);
4618
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004619 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004620
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004621 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004622}
4623
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004624static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004625{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004626 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004627 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004628 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004629
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004630 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004631
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004632 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004633 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004634 rp.tx_power = conn->tx_power;
4635 rp.max_tx_power = conn->max_tx_power;
4636 } else {
4637 rp.rssi = HCI_RSSI_INVALID;
4638 rp.tx_power = HCI_TX_POWER_INVALID;
4639 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004640 }
4641
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004642 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4643 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004644
4645 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004646 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004647
4648 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004649}
4650
Marcel Holtmann1904a852015-01-11 13:50:44 -08004651static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4652 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004653{
4654 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004655 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004656 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004657 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004658 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004659
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004660 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004661
4662 hci_dev_lock(hdev);
4663
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004664 /* Commands sent in request are either Read RSSI or Read Transmit Power
4665 * Level so we check which one was last sent to retrieve connection
4666 * handle. Both commands have handle as first parameter so it's safe to
4667 * cast data on the same command struct.
4668 *
4669 * First command sent is always Read RSSI and we fail only if it fails.
4670 * In other case we simply override error to indicate success as we
4671 * already remembered if TX power value is actually valid.
4672 */
4673 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4674 if (!cp) {
4675 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004676 status = MGMT_STATUS_SUCCESS;
4677 } else {
4678 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004679 }
4680
4681 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004682 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004683 goto unlock;
4684 }
4685
4686 handle = __le16_to_cpu(cp->handle);
4687 conn = hci_conn_hash_lookup_handle(hdev, handle);
4688 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004689 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004690 goto unlock;
4691 }
4692
Johan Hedberg333ae952015-03-17 13:48:47 +02004693 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004694 if (!cmd)
4695 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004696
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004697 cmd->cmd_complete(cmd, status);
4698 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004699
4700unlock:
4701 hci_dev_unlock(hdev);
4702}
4703
4704static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4705 u16 len)
4706{
4707 struct mgmt_cp_get_conn_info *cp = data;
4708 struct mgmt_rp_get_conn_info rp;
4709 struct hci_conn *conn;
4710 unsigned long conn_info_age;
4711 int err = 0;
4712
4713 BT_DBG("%s", hdev->name);
4714
4715 memset(&rp, 0, sizeof(rp));
4716 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4717 rp.addr.type = cp->addr.type;
4718
4719 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004720 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4721 MGMT_STATUS_INVALID_PARAMS,
4722 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004723
4724 hci_dev_lock(hdev);
4725
4726 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004727 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4728 MGMT_STATUS_NOT_POWERED, &rp,
4729 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004730 goto unlock;
4731 }
4732
4733 if (cp->addr.type == BDADDR_BREDR)
4734 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4735 &cp->addr.bdaddr);
4736 else
4737 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4738
4739 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004740 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4741 MGMT_STATUS_NOT_CONNECTED, &rp,
4742 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004743 goto unlock;
4744 }
4745
Johan Hedberg333ae952015-03-17 13:48:47 +02004746 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004747 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4748 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004749 goto unlock;
4750 }
4751
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004752 /* To avoid client trying to guess when to poll again for information we
4753 * calculate conn info age as random value between min/max set in hdev.
4754 */
4755 conn_info_age = hdev->conn_info_min_age +
4756 prandom_u32_max(hdev->conn_info_max_age -
4757 hdev->conn_info_min_age);
4758
4759 /* Query controller to refresh cached values if they are too old or were
4760 * never read.
4761 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004762 if (time_after(jiffies, conn->conn_info_timestamp +
4763 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004764 !conn->conn_info_timestamp) {
4765 struct hci_request req;
4766 struct hci_cp_read_tx_power req_txp_cp;
4767 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004768 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004769
4770 hci_req_init(&req, hdev);
4771 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4772 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4773 &req_rssi_cp);
4774
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004775 /* For LE links TX power does not change thus we don't need to
4776 * query for it once value is known.
4777 */
4778 if (!bdaddr_type_is_le(cp->addr.type) ||
4779 conn->tx_power == HCI_TX_POWER_INVALID) {
4780 req_txp_cp.handle = cpu_to_le16(conn->handle);
4781 req_txp_cp.type = 0x00;
4782 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4783 sizeof(req_txp_cp), &req_txp_cp);
4784 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004785
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004786 /* Max TX power needs to be read only once per connection */
4787 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4788 req_txp_cp.handle = cpu_to_le16(conn->handle);
4789 req_txp_cp.type = 0x01;
4790 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4791 sizeof(req_txp_cp), &req_txp_cp);
4792 }
4793
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004794 err = hci_req_run(&req, conn_info_refresh_complete);
4795 if (err < 0)
4796 goto unlock;
4797
4798 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4799 data, len);
4800 if (!cmd) {
4801 err = -ENOMEM;
4802 goto unlock;
4803 }
4804
4805 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004806 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004807 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004808
4809 conn->conn_info_timestamp = jiffies;
4810 } else {
4811 /* Cache is valid, just reply with values cached in hci_conn */
4812 rp.rssi = conn->rssi;
4813 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004814 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004815
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004816 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4817 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004818 }
4819
4820unlock:
4821 hci_dev_unlock(hdev);
4822 return err;
4823}
4824
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004825static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004826{
4827 struct hci_conn *conn = cmd->user_data;
4828 struct mgmt_rp_get_clock_info rp;
4829 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004830 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004831
4832 memset(&rp, 0, sizeof(rp));
4833 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
4834
4835 if (status)
4836 goto complete;
4837
4838 hdev = hci_dev_get(cmd->index);
4839 if (hdev) {
4840 rp.local_clock = cpu_to_le32(hdev->clock);
4841 hci_dev_put(hdev);
4842 }
4843
4844 if (conn) {
4845 rp.piconet_clock = cpu_to_le32(conn->clock);
4846 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
4847 }
4848
4849complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004850 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
4851 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02004852
4853 if (conn) {
4854 hci_conn_drop(conn);
4855 hci_conn_put(conn);
4856 }
Johan Hedberg9df74652014-12-19 22:26:03 +02004857
4858 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02004859}
4860
Marcel Holtmann1904a852015-01-11 13:50:44 -08004861static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03004862{
Johan Hedberg95868422014-06-28 17:54:07 +03004863 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004864 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004865 struct hci_conn *conn;
4866
4867 BT_DBG("%s status %u", hdev->name, status);
4868
4869 hci_dev_lock(hdev);
4870
4871 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
4872 if (!hci_cp)
4873 goto unlock;
4874
4875 if (hci_cp->which) {
4876 u16 handle = __le16_to_cpu(hci_cp->handle);
4877 conn = hci_conn_hash_lookup_handle(hdev, handle);
4878 } else {
4879 conn = NULL;
4880 }
4881
Johan Hedberg333ae952015-03-17 13:48:47 +02004882 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004883 if (!cmd)
4884 goto unlock;
4885
Johan Hedberg69487372014-12-05 13:36:07 +02004886 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03004887 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03004888
4889unlock:
4890 hci_dev_unlock(hdev);
4891}
4892
4893static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
4894 u16 len)
4895{
4896 struct mgmt_cp_get_clock_info *cp = data;
4897 struct mgmt_rp_get_clock_info rp;
4898 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004899 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004900 struct hci_request req;
4901 struct hci_conn *conn;
4902 int err;
4903
4904 BT_DBG("%s", hdev->name);
4905
4906 memset(&rp, 0, sizeof(rp));
4907 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4908 rp.addr.type = cp->addr.type;
4909
4910 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004911 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4912 MGMT_STATUS_INVALID_PARAMS,
4913 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004914
4915 hci_dev_lock(hdev);
4916
4917 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004918 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4919 MGMT_STATUS_NOT_POWERED, &rp,
4920 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004921 goto unlock;
4922 }
4923
4924 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4925 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4926 &cp->addr.bdaddr);
4927 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004928 err = mgmt_cmd_complete(sk, hdev->id,
4929 MGMT_OP_GET_CLOCK_INFO,
4930 MGMT_STATUS_NOT_CONNECTED,
4931 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004932 goto unlock;
4933 }
4934 } else {
4935 conn = NULL;
4936 }
4937
4938 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
4939 if (!cmd) {
4940 err = -ENOMEM;
4941 goto unlock;
4942 }
4943
Johan Hedberg69487372014-12-05 13:36:07 +02004944 cmd->cmd_complete = clock_info_cmd_complete;
4945
Johan Hedberg95868422014-06-28 17:54:07 +03004946 hci_req_init(&req, hdev);
4947
4948 memset(&hci_cp, 0, sizeof(hci_cp));
4949 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4950
4951 if (conn) {
4952 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004953 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004954
4955 hci_cp.handle = cpu_to_le16(conn->handle);
4956 hci_cp.which = 0x01; /* Piconet clock */
4957 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4958 }
4959
4960 err = hci_req_run(&req, get_clock_info_complete);
4961 if (err < 0)
4962 mgmt_pending_remove(cmd);
4963
4964unlock:
4965 hci_dev_unlock(hdev);
4966 return err;
4967}
4968
Johan Hedberg5a154e62014-12-19 22:26:02 +02004969static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
4970{
4971 struct hci_conn *conn;
4972
4973 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
4974 if (!conn)
4975 return false;
4976
4977 if (conn->dst_type != type)
4978 return false;
4979
4980 if (conn->state != BT_CONNECTED)
4981 return false;
4982
4983 return true;
4984}
4985
4986/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02004987static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02004988 u8 addr_type, u8 auto_connect)
4989{
Johan Hedberg5a154e62014-12-19 22:26:02 +02004990 struct hci_conn_params *params;
4991
4992 params = hci_conn_params_add(hdev, addr, addr_type);
4993 if (!params)
4994 return -EIO;
4995
4996 if (params->auto_connect == auto_connect)
4997 return 0;
4998
4999 list_del_init(&params->action);
5000
5001 switch (auto_connect) {
5002 case HCI_AUTO_CONN_DISABLED:
5003 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005004 /* If auto connect is being disabled when we're trying to
5005 * connect to device, keep connecting.
5006 */
5007 if (params->explicit_connect)
5008 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005009 break;
5010 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005011 if (params->explicit_connect)
5012 list_add(&params->action, &hdev->pend_le_conns);
5013 else
5014 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005015 break;
5016 case HCI_AUTO_CONN_DIRECT:
5017 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005018 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005019 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005020 break;
5021 }
5022
5023 params->auto_connect = auto_connect;
5024
5025 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5026 auto_connect);
5027
5028 return 0;
5029}
5030
Marcel Holtmann8afef092014-06-29 22:28:34 +02005031static void device_added(struct sock *sk, struct hci_dev *hdev,
5032 bdaddr_t *bdaddr, u8 type, u8 action)
5033{
5034 struct mgmt_ev_device_added ev;
5035
5036 bacpy(&ev.addr.bdaddr, bdaddr);
5037 ev.addr.type = type;
5038 ev.action = action;
5039
5040 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5041}
5042
Marcel Holtmann2faade52014-06-29 19:44:03 +02005043static int add_device(struct sock *sk, struct hci_dev *hdev,
5044 void *data, u16 len)
5045{
5046 struct mgmt_cp_add_device *cp = data;
5047 u8 auto_conn, addr_type;
5048 int err;
5049
5050 BT_DBG("%s", hdev->name);
5051
Johan Hedberg66593582014-07-09 12:59:14 +03005052 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005053 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005054 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5055 MGMT_STATUS_INVALID_PARAMS,
5056 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005057
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005058 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005059 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5060 MGMT_STATUS_INVALID_PARAMS,
5061 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005062
5063 hci_dev_lock(hdev);
5064
Johan Hedberg66593582014-07-09 12:59:14 +03005065 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005066 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005067 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005068 err = mgmt_cmd_complete(sk, hdev->id,
5069 MGMT_OP_ADD_DEVICE,
5070 MGMT_STATUS_INVALID_PARAMS,
5071 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005072 goto unlock;
5073 }
5074
5075 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5076 cp->addr.type);
5077 if (err)
5078 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005079
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005080 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005081
Johan Hedberg66593582014-07-09 12:59:14 +03005082 goto added;
5083 }
5084
Johan Hedberg85813a72015-10-21 18:02:59 +03005085 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005086
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005087 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005088 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005089 else if (cp->action == 0x01)
5090 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005091 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005092 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005093
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005094 /* Kernel internally uses conn_params with resolvable private
5095 * address, but Add Device allows only identity addresses.
5096 * Make sure it is enforced before calling
5097 * hci_conn_params_lookup.
5098 */
5099 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005100 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5101 MGMT_STATUS_INVALID_PARAMS,
5102 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005103 goto unlock;
5104 }
5105
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005106 /* If the connection parameters don't exist for this device,
5107 * they will be created and configured with defaults.
5108 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005109 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005110 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005111 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5112 MGMT_STATUS_FAILED, &cp->addr,
5113 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005114 goto unlock;
5115 }
5116
Johan Hedberg51d7a942015-11-11 08:11:18 +02005117 hci_update_background_scan(hdev);
5118
Johan Hedberg66593582014-07-09 12:59:14 +03005119added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005120 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5121
Johan Hedberg51d7a942015-11-11 08:11:18 +02005122 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5123 MGMT_STATUS_SUCCESS, &cp->addr,
5124 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005125
5126unlock:
5127 hci_dev_unlock(hdev);
5128 return err;
5129}
5130
Marcel Holtmann8afef092014-06-29 22:28:34 +02005131static void device_removed(struct sock *sk, struct hci_dev *hdev,
5132 bdaddr_t *bdaddr, u8 type)
5133{
5134 struct mgmt_ev_device_removed ev;
5135
5136 bacpy(&ev.addr.bdaddr, bdaddr);
5137 ev.addr.type = type;
5138
5139 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5140}
5141
Marcel Holtmann2faade52014-06-29 19:44:03 +02005142static int remove_device(struct sock *sk, struct hci_dev *hdev,
5143 void *data, u16 len)
5144{
5145 struct mgmt_cp_remove_device *cp = data;
5146 int err;
5147
5148 BT_DBG("%s", hdev->name);
5149
5150 hci_dev_lock(hdev);
5151
5152 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005153 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005154 u8 addr_type;
5155
Johan Hedberg66593582014-07-09 12:59:14 +03005156 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005157 err = mgmt_cmd_complete(sk, hdev->id,
5158 MGMT_OP_REMOVE_DEVICE,
5159 MGMT_STATUS_INVALID_PARAMS,
5160 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005161 goto unlock;
5162 }
5163
Johan Hedberg66593582014-07-09 12:59:14 +03005164 if (cp->addr.type == BDADDR_BREDR) {
5165 err = hci_bdaddr_list_del(&hdev->whitelist,
5166 &cp->addr.bdaddr,
5167 cp->addr.type);
5168 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005169 err = mgmt_cmd_complete(sk, hdev->id,
5170 MGMT_OP_REMOVE_DEVICE,
5171 MGMT_STATUS_INVALID_PARAMS,
5172 &cp->addr,
5173 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005174 goto unlock;
5175 }
5176
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005177 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005178
Johan Hedberg66593582014-07-09 12:59:14 +03005179 device_removed(sk, hdev, &cp->addr.bdaddr,
5180 cp->addr.type);
5181 goto complete;
5182 }
5183
Johan Hedberg85813a72015-10-21 18:02:59 +03005184 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005185
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005186 /* Kernel internally uses conn_params with resolvable private
5187 * address, but Remove Device allows only identity addresses.
5188 * Make sure it is enforced before calling
5189 * hci_conn_params_lookup.
5190 */
5191 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005192 err = mgmt_cmd_complete(sk, hdev->id,
5193 MGMT_OP_REMOVE_DEVICE,
5194 MGMT_STATUS_INVALID_PARAMS,
5195 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005196 goto unlock;
5197 }
5198
Johan Hedbergc71593d2014-07-02 17:37:28 +03005199 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5200 addr_type);
5201 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005202 err = mgmt_cmd_complete(sk, hdev->id,
5203 MGMT_OP_REMOVE_DEVICE,
5204 MGMT_STATUS_INVALID_PARAMS,
5205 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005206 goto unlock;
5207 }
5208
Johan Hedberg679d2b62015-10-16 10:07:52 +03005209 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5210 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005211 err = mgmt_cmd_complete(sk, hdev->id,
5212 MGMT_OP_REMOVE_DEVICE,
5213 MGMT_STATUS_INVALID_PARAMS,
5214 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005215 goto unlock;
5216 }
5217
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005218 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005219 list_del(&params->list);
5220 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005221 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005222
5223 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005224 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005225 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005226 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005227
Marcel Holtmann2faade52014-06-29 19:44:03 +02005228 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005229 err = mgmt_cmd_complete(sk, hdev->id,
5230 MGMT_OP_REMOVE_DEVICE,
5231 MGMT_STATUS_INVALID_PARAMS,
5232 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005233 goto unlock;
5234 }
5235
Johan Hedberg66593582014-07-09 12:59:14 +03005236 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5237 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5238 list_del(&b->list);
5239 kfree(b);
5240 }
5241
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005242 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005243
Johan Hedberg19de0822014-07-06 13:06:51 +03005244 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5245 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5246 continue;
5247 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005248 if (p->explicit_connect) {
5249 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5250 continue;
5251 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005252 list_del(&p->action);
5253 list_del(&p->list);
5254 kfree(p);
5255 }
5256
5257 BT_DBG("All LE connection parameters were removed");
5258
Johan Hedberg51d7a942015-11-11 08:11:18 +02005259 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005260 }
5261
Johan Hedberg66593582014-07-09 12:59:14 +03005262complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005263 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5264 MGMT_STATUS_SUCCESS, &cp->addr,
5265 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005266unlock:
5267 hci_dev_unlock(hdev);
5268 return err;
5269}
5270
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005271static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5272 u16 len)
5273{
5274 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005275 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5276 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005277 u16 param_count, expected_len;
5278 int i;
5279
5280 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005281 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5282 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005283
5284 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005285 if (param_count > max_param_count) {
5286 BT_ERR("load_conn_param: too big param_count value %u",
5287 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005288 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5289 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005290 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005291
5292 expected_len = sizeof(*cp) + param_count *
5293 sizeof(struct mgmt_conn_param);
5294 if (expected_len != len) {
5295 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5296 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005297 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5298 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005299 }
5300
5301 BT_DBG("%s param_count %u", hdev->name, param_count);
5302
5303 hci_dev_lock(hdev);
5304
5305 hci_conn_params_clear_disabled(hdev);
5306
5307 for (i = 0; i < param_count; i++) {
5308 struct mgmt_conn_param *param = &cp->params[i];
5309 struct hci_conn_params *hci_param;
5310 u16 min, max, latency, timeout;
5311 u8 addr_type;
5312
5313 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5314 param->addr.type);
5315
5316 if (param->addr.type == BDADDR_LE_PUBLIC) {
5317 addr_type = ADDR_LE_DEV_PUBLIC;
5318 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5319 addr_type = ADDR_LE_DEV_RANDOM;
5320 } else {
5321 BT_ERR("Ignoring invalid connection parameters");
5322 continue;
5323 }
5324
5325 min = le16_to_cpu(param->min_interval);
5326 max = le16_to_cpu(param->max_interval);
5327 latency = le16_to_cpu(param->latency);
5328 timeout = le16_to_cpu(param->timeout);
5329
5330 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5331 min, max, latency, timeout);
5332
5333 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5334 BT_ERR("Ignoring invalid connection parameters");
5335 continue;
5336 }
5337
5338 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5339 addr_type);
5340 if (!hci_param) {
5341 BT_ERR("Failed to add connection parameters");
5342 continue;
5343 }
5344
5345 hci_param->conn_min_interval = min;
5346 hci_param->conn_max_interval = max;
5347 hci_param->conn_latency = latency;
5348 hci_param->supervision_timeout = timeout;
5349 }
5350
5351 hci_dev_unlock(hdev);
5352
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005353 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5354 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005355}
5356
Marcel Holtmanndbece372014-07-04 18:11:55 +02005357static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5358 void *data, u16 len)
5359{
5360 struct mgmt_cp_set_external_config *cp = data;
5361 bool changed;
5362 int err;
5363
5364 BT_DBG("%s", hdev->name);
5365
5366 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005367 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5368 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005369
5370 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005371 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5372 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005373
5374 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005375 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5376 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005377
5378 hci_dev_lock(hdev);
5379
5380 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005381 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005382 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005383 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005384
5385 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5386 if (err < 0)
5387 goto unlock;
5388
5389 if (!changed)
5390 goto unlock;
5391
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005392 err = new_options(hdev, sk);
5393
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005394 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005395 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005396
Marcel Holtmann516018a2015-03-13 02:11:04 -07005397 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005398 hci_dev_set_flag(hdev, HCI_CONFIG);
5399 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005400
5401 queue_work(hdev->req_workqueue, &hdev->power_on);
5402 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005403 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005404 mgmt_index_added(hdev);
5405 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005406 }
5407
5408unlock:
5409 hci_dev_unlock(hdev);
5410 return err;
5411}
5412
Marcel Holtmann9713c172014-07-06 12:11:15 +02005413static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5414 void *data, u16 len)
5415{
5416 struct mgmt_cp_set_public_address *cp = data;
5417 bool changed;
5418 int err;
5419
5420 BT_DBG("%s", hdev->name);
5421
5422 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005423 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5424 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005425
5426 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005427 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5428 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005429
5430 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005431 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5432 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005433
5434 hci_dev_lock(hdev);
5435
5436 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5437 bacpy(&hdev->public_addr, &cp->bdaddr);
5438
5439 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5440 if (err < 0)
5441 goto unlock;
5442
5443 if (!changed)
5444 goto unlock;
5445
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005446 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005447 err = new_options(hdev, sk);
5448
5449 if (is_configured(hdev)) {
5450 mgmt_index_removed(hdev);
5451
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005452 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005453
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005454 hci_dev_set_flag(hdev, HCI_CONFIG);
5455 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005456
5457 queue_work(hdev->req_workqueue, &hdev->power_on);
5458 }
5459
5460unlock:
5461 hci_dev_unlock(hdev);
5462 return err;
5463}
5464
Marcel Holtmannbea41602015-03-14 22:43:17 -07005465static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5466 u8 data_len)
5467{
5468 eir[eir_len++] = sizeof(type) + data_len;
5469 eir[eir_len++] = type;
5470 memcpy(&eir[eir_len], data, data_len);
5471 eir_len += data_len;
5472
5473 return eir_len;
5474}
5475
Johan Hedberg40f66c02015-04-07 21:52:22 +03005476static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5477 u16 opcode, struct sk_buff *skb)
5478{
5479 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5480 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5481 u8 *h192, *r192, *h256, *r256;
5482 struct mgmt_pending_cmd *cmd;
5483 u16 eir_len;
5484 int err;
5485
5486 BT_DBG("%s status %u", hdev->name, status);
5487
5488 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5489 if (!cmd)
5490 return;
5491
5492 mgmt_cp = cmd->param;
5493
5494 if (status) {
5495 status = mgmt_status(status);
5496 eir_len = 0;
5497
5498 h192 = NULL;
5499 r192 = NULL;
5500 h256 = NULL;
5501 r256 = NULL;
5502 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5503 struct hci_rp_read_local_oob_data *rp;
5504
5505 if (skb->len != sizeof(*rp)) {
5506 status = MGMT_STATUS_FAILED;
5507 eir_len = 0;
5508 } else {
5509 status = MGMT_STATUS_SUCCESS;
5510 rp = (void *)skb->data;
5511
5512 eir_len = 5 + 18 + 18;
5513 h192 = rp->hash;
5514 r192 = rp->rand;
5515 h256 = NULL;
5516 r256 = NULL;
5517 }
5518 } else {
5519 struct hci_rp_read_local_oob_ext_data *rp;
5520
5521 if (skb->len != sizeof(*rp)) {
5522 status = MGMT_STATUS_FAILED;
5523 eir_len = 0;
5524 } else {
5525 status = MGMT_STATUS_SUCCESS;
5526 rp = (void *)skb->data;
5527
5528 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5529 eir_len = 5 + 18 + 18;
5530 h192 = NULL;
5531 r192 = NULL;
5532 } else {
5533 eir_len = 5 + 18 + 18 + 18 + 18;
5534 h192 = rp->hash192;
5535 r192 = rp->rand192;
5536 }
5537
5538 h256 = rp->hash256;
5539 r256 = rp->rand256;
5540 }
5541 }
5542
5543 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5544 if (!mgmt_rp)
5545 goto done;
5546
5547 if (status)
5548 goto send_rsp;
5549
5550 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5551 hdev->dev_class, 3);
5552
5553 if (h192 && r192) {
5554 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5555 EIR_SSP_HASH_C192, h192, 16);
5556 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5557 EIR_SSP_RAND_R192, r192, 16);
5558 }
5559
5560 if (h256 && r256) {
5561 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5562 EIR_SSP_HASH_C256, h256, 16);
5563 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5564 EIR_SSP_RAND_R256, r256, 16);
5565 }
5566
5567send_rsp:
5568 mgmt_rp->type = mgmt_cp->type;
5569 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5570
5571 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5572 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5573 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5574 if (err < 0 || status)
5575 goto done;
5576
5577 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5578
5579 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5580 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5581 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5582done:
5583 kfree(mgmt_rp);
5584 mgmt_pending_remove(cmd);
5585}
5586
5587static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5588 struct mgmt_cp_read_local_oob_ext_data *cp)
5589{
5590 struct mgmt_pending_cmd *cmd;
5591 struct hci_request req;
5592 int err;
5593
5594 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5595 cp, sizeof(*cp));
5596 if (!cmd)
5597 return -ENOMEM;
5598
5599 hci_req_init(&req, hdev);
5600
5601 if (bredr_sc_enabled(hdev))
5602 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5603 else
5604 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5605
5606 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5607 if (err < 0) {
5608 mgmt_pending_remove(cmd);
5609 return err;
5610 }
5611
5612 return 0;
5613}
5614
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005615static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5616 void *data, u16 data_len)
5617{
5618 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5619 struct mgmt_rp_read_local_oob_ext_data *rp;
5620 size_t rp_len;
5621 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005622 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005623 int err;
5624
5625 BT_DBG("%s", hdev->name);
5626
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005627 if (hdev_is_powered(hdev)) {
5628 switch (cp->type) {
5629 case BIT(BDADDR_BREDR):
5630 status = mgmt_bredr_support(hdev);
5631 if (status)
5632 eir_len = 0;
5633 else
5634 eir_len = 5;
5635 break;
5636 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5637 status = mgmt_le_support(hdev);
5638 if (status)
5639 eir_len = 0;
5640 else
5641 eir_len = 9 + 3 + 18 + 18 + 3;
5642 break;
5643 default:
5644 status = MGMT_STATUS_INVALID_PARAMS;
5645 eir_len = 0;
5646 break;
5647 }
5648 } else {
5649 status = MGMT_STATUS_NOT_POWERED;
5650 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005651 }
5652
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005653 rp_len = sizeof(*rp) + eir_len;
5654 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005655 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005656 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005657
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005658 if (status)
5659 goto complete;
5660
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005661 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005662
5663 eir_len = 0;
5664 switch (cp->type) {
5665 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005666 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5667 err = read_local_ssp_oob_req(hdev, sk, cp);
5668 hci_dev_unlock(hdev);
5669 if (!err)
5670 goto done;
5671
5672 status = MGMT_STATUS_FAILED;
5673 goto complete;
5674 } else {
5675 eir_len = eir_append_data(rp->eir, eir_len,
5676 EIR_CLASS_OF_DEV,
5677 hdev->dev_class, 3);
5678 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005679 break;
5680 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005681 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5682 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005683 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005684 status = MGMT_STATUS_FAILED;
5685 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005686 }
5687
Marcel Holtmanne2135682015-04-02 12:00:58 -07005688 /* This should return the active RPA, but since the RPA
5689 * is only programmed on demand, it is really hard to fill
5690 * this in at the moment. For now disallow retrieving
5691 * local out-of-band data when privacy is in use.
5692 *
5693 * Returning the identity address will not help here since
5694 * pairing happens before the identity resolving key is
5695 * known and thus the connection establishment happens
5696 * based on the RPA and not the identity address.
5697 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005698 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005699 hci_dev_unlock(hdev);
5700 status = MGMT_STATUS_REJECTED;
5701 goto complete;
5702 }
5703
5704 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5705 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5706 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5707 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005708 memcpy(addr, &hdev->static_addr, 6);
5709 addr[6] = 0x01;
5710 } else {
5711 memcpy(addr, &hdev->bdaddr, 6);
5712 addr[6] = 0x00;
5713 }
5714
5715 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5716 addr, sizeof(addr));
5717
5718 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5719 role = 0x02;
5720 else
5721 role = 0x01;
5722
5723 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5724 &role, sizeof(role));
5725
Marcel Holtmann5082a592015-03-16 12:39:00 -07005726 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5727 eir_len = eir_append_data(rp->eir, eir_len,
5728 EIR_LE_SC_CONFIRM,
5729 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005730
Marcel Holtmann5082a592015-03-16 12:39:00 -07005731 eir_len = eir_append_data(rp->eir, eir_len,
5732 EIR_LE_SC_RANDOM,
5733 rand, sizeof(rand));
5734 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005735
Johan Hedbergf2252572015-11-18 12:49:20 +02005736 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005737
5738 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5739 flags |= LE_AD_NO_BREDR;
5740
5741 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5742 &flags, sizeof(flags));
5743 break;
5744 }
5745
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005746 hci_dev_unlock(hdev);
5747
Marcel Holtmann72000df2015-03-16 16:11:21 -07005748 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5749
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005750 status = MGMT_STATUS_SUCCESS;
5751
5752complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005753 rp->type = cp->type;
5754 rp->eir_len = cpu_to_le16(eir_len);
5755
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005756 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005757 status, rp, sizeof(*rp) + eir_len);
5758 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005759 goto done;
5760
5761 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5762 rp, sizeof(*rp) + eir_len,
5763 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005764
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005765done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005766 kfree(rp);
5767
5768 return err;
5769}
5770
Arman Uguray089fa8c2015-03-25 18:53:45 -07005771static u32 get_supported_adv_flags(struct hci_dev *hdev)
5772{
5773 u32 flags = 0;
5774
5775 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5776 flags |= MGMT_ADV_FLAG_DISCOV;
5777 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5778 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
5779
5780 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5781 flags |= MGMT_ADV_FLAG_TX_POWER;
5782
5783 return flags;
5784}
5785
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005786static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5787 void *data, u16 data_len)
5788{
5789 struct mgmt_rp_read_adv_features *rp;
5790 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005791 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005792 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005793 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005794 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005795
5796 BT_DBG("%s", hdev->name);
5797
Arman Uguray089fa8c2015-03-25 18:53:45 -07005798 if (!lmp_le_capable(hdev))
5799 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5800 MGMT_STATUS_REJECTED);
5801
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005802 hci_dev_lock(hdev);
5803
Johan Hedberg02c04af2015-11-26 12:15:58 +02005804 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005805 rp = kmalloc(rp_len, GFP_ATOMIC);
5806 if (!rp) {
5807 hci_dev_unlock(hdev);
5808 return -ENOMEM;
5809 }
5810
Arman Uguray089fa8c2015-03-25 18:53:45 -07005811 supported_flags = get_supported_adv_flags(hdev);
5812
5813 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005814 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5815 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005816 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005817 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005818
Johan Hedberg02c04af2015-11-26 12:15:58 +02005819 instance = rp->instance;
5820 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5821 *instance = adv_instance->instance;
5822 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005823 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005824
5825 hci_dev_unlock(hdev);
5826
5827 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5828 MGMT_STATUS_SUCCESS, rp, rp_len);
5829
5830 kfree(rp);
5831
5832 return err;
5833}
5834
Arman Uguray4117ed72015-03-23 15:57:14 -07005835static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005836 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005837{
Arman Uguray4117ed72015-03-23 15:57:14 -07005838 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005839 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005840 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005841 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005842
Marcel Holtmann31a32482015-11-19 16:16:42 +01005843 if (is_adv_data) {
5844 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5845 MGMT_ADV_FLAG_LIMITED_DISCOV |
5846 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5847 flags_managed = true;
5848 max_len -= 3;
5849 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005850
Marcel Holtmann31a32482015-11-19 16:16:42 +01005851 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5852 tx_power_managed = true;
5853 max_len -= 3;
5854 }
Arman Uguray5507e352015-03-25 18:53:44 -07005855 }
5856
Arman Uguray4117ed72015-03-23 15:57:14 -07005857 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005858 return false;
5859
Arman Uguray4117ed72015-03-23 15:57:14 -07005860 /* Make sure that the data is correctly formatted. */
5861 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
5862 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07005863
Arman Ugurayb44133f2015-03-25 18:53:41 -07005864 if (flags_managed && data[i + 1] == EIR_FLAGS)
5865 return false;
5866
Arman Uguray5507e352015-03-25 18:53:44 -07005867 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
5868 return false;
5869
Arman Uguray24b4f382015-03-23 15:57:12 -07005870 /* If the current field length would exceed the total data
5871 * length, then it's invalid.
5872 */
Arman Uguray4117ed72015-03-23 15:57:14 -07005873 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005874 return false;
5875 }
5876
5877 return true;
5878}
5879
Arman Uguray24b4f382015-03-23 15:57:12 -07005880static void add_advertising_complete(struct hci_dev *hdev, u8 status,
5881 u16 opcode)
5882{
5883 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005884 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07005885 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005886 struct adv_info *adv_instance, *n;
5887 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005888
5889 BT_DBG("status %d", status);
5890
5891 hci_dev_lock(hdev);
5892
5893 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
5894
Florian Grandelfffd38b2015-06-18 03:16:47 +02005895 if (status)
Arman Uguray24b4f382015-03-23 15:57:12 -07005896 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005897
5898 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
5899 if (!adv_instance->pending)
5900 continue;
5901
5902 if (!status) {
5903 adv_instance->pending = false;
5904 continue;
5905 }
5906
5907 instance = adv_instance->instance;
5908
5909 if (hdev->cur_adv_instance == instance)
5910 cancel_adv_timeout(hdev);
5911
5912 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02005913 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07005914 }
5915
5916 if (!cmd)
5917 goto unlock;
5918
Florian Grandelfffd38b2015-06-18 03:16:47 +02005919 cp = cmd->param;
5920 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005921
5922 if (status)
5923 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5924 mgmt_status(status));
5925 else
5926 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
5927 mgmt_status(status), &rp, sizeof(rp));
5928
5929 mgmt_pending_remove(cmd);
5930
5931unlock:
5932 hci_dev_unlock(hdev);
5933}
5934
5935static int add_advertising(struct sock *sk, struct hci_dev *hdev,
5936 void *data, u16 data_len)
5937{
5938 struct mgmt_cp_add_advertising *cp = data;
5939 struct mgmt_rp_add_advertising rp;
5940 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005941 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07005942 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005943 u16 timeout, duration;
5944 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
5945 u8 schedule_instance = 0;
5946 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005947 int err;
5948 struct mgmt_pending_cmd *cmd;
5949 struct hci_request req;
5950
5951 BT_DBG("%s", hdev->name);
5952
5953 status = mgmt_le_support(hdev);
5954 if (status)
5955 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5956 status);
5957
Marcel Holtmannceff86a2015-11-19 16:16:41 +01005958 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
5959 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5960 MGMT_STATUS_INVALID_PARAMS);
5961
Arman Uguray24b4f382015-03-23 15:57:12 -07005962 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07005963 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005964 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07005965
Florian Grandelfffd38b2015-06-18 03:16:47 +02005966 /* The current implementation only supports a subset of the specified
5967 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07005968 */
5969 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005970 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07005971 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5972 MGMT_STATUS_INVALID_PARAMS);
5973
5974 hci_dev_lock(hdev);
5975
Arman Uguray912098a2015-03-23 15:57:15 -07005976 if (timeout && !hdev_is_powered(hdev)) {
5977 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5978 MGMT_STATUS_REJECTED);
5979 goto unlock;
5980 }
5981
Arman Uguray24b4f382015-03-23 15:57:12 -07005982 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07005983 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07005984 pending_find(MGMT_OP_SET_LE, hdev)) {
5985 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5986 MGMT_STATUS_BUSY);
5987 goto unlock;
5988 }
5989
Arman Ugurayb44133f2015-03-25 18:53:41 -07005990 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07005991 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005992 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07005993 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5994 MGMT_STATUS_INVALID_PARAMS);
5995 goto unlock;
5996 }
5997
Florian Grandelfffd38b2015-06-18 03:16:47 +02005998 err = hci_add_adv_instance(hdev, cp->instance, flags,
5999 cp->adv_data_len, cp->data,
6000 cp->scan_rsp_len,
6001 cp->data + cp->adv_data_len,
6002 timeout, duration);
6003 if (err < 0) {
6004 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6005 MGMT_STATUS_FAILED);
6006 goto unlock;
6007 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006008
Florian Grandelfffd38b2015-06-18 03:16:47 +02006009 /* Only trigger an advertising added event if a new instance was
6010 * actually added.
6011 */
6012 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006013 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006014
Florian Grandelfffd38b2015-06-18 03:16:47 +02006015 hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
Arman Uguray24b4f382015-03-23 15:57:12 -07006016
Florian Grandelfffd38b2015-06-18 03:16:47 +02006017 if (hdev->cur_adv_instance == cp->instance) {
6018 /* If the currently advertised instance is being changed then
6019 * cancel the current advertising and schedule the next
6020 * instance. If there is only one instance then the overridden
6021 * advertising data will be visible right away.
6022 */
6023 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006024
Florian Grandelfffd38b2015-06-18 03:16:47 +02006025 next_instance = hci_get_next_instance(hdev, cp->instance);
6026 if (next_instance)
6027 schedule_instance = next_instance->instance;
6028 } else if (!hdev->adv_instance_timeout) {
6029 /* Immediately advertise the new instance if no other
6030 * instance is currently being advertised.
6031 */
6032 schedule_instance = cp->instance;
6033 }
Arman Uguray912098a2015-03-23 15:57:15 -07006034
Florian Grandelfffd38b2015-06-18 03:16:47 +02006035 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6036 * there is no instance to be advertised then we have no HCI
6037 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006038 */
6039 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006040 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6041 !schedule_instance) {
6042 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006043 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6044 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6045 goto unlock;
6046 }
6047
6048 /* We're good to go, update advertising data, parameters, and start
6049 * advertising.
6050 */
6051 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6052 data_len);
6053 if (!cmd) {
6054 err = -ENOMEM;
6055 goto unlock;
6056 }
6057
6058 hci_req_init(&req, hdev);
6059
Johan Hedbergf2252572015-11-18 12:49:20 +02006060 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006061
Florian Grandelfffd38b2015-06-18 03:16:47 +02006062 if (!err)
6063 err = hci_req_run(&req, add_advertising_complete);
6064
Arman Uguray24b4f382015-03-23 15:57:12 -07006065 if (err < 0)
6066 mgmt_pending_remove(cmd);
6067
6068unlock:
6069 hci_dev_unlock(hdev);
6070
6071 return err;
6072}
6073
Arman Ugurayda9293352015-03-23 15:57:13 -07006074static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6075 u16 opcode)
6076{
6077 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006078 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006079 struct mgmt_rp_remove_advertising rp;
6080
6081 BT_DBG("status %d", status);
6082
6083 hci_dev_lock(hdev);
6084
6085 /* A failure status here only means that we failed to disable
6086 * advertising. Otherwise, the advertising instance has been removed,
6087 * so report success.
6088 */
6089 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6090 if (!cmd)
6091 goto unlock;
6092
Florian Grandel01948332015-06-18 03:16:48 +02006093 cp = cmd->param;
6094 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006095
6096 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6097 &rp, sizeof(rp));
6098 mgmt_pending_remove(cmd);
6099
6100unlock:
6101 hci_dev_unlock(hdev);
6102}
6103
6104static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6105 void *data, u16 data_len)
6106{
6107 struct mgmt_cp_remove_advertising *cp = data;
6108 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006109 struct mgmt_pending_cmd *cmd;
6110 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006111 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006112
6113 BT_DBG("%s", hdev->name);
6114
Arman Ugurayda9293352015-03-23 15:57:13 -07006115 hci_dev_lock(hdev);
6116
Johan Hedberg952497b2015-06-18 21:05:31 +03006117 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006118 err = mgmt_cmd_status(sk, hdev->id,
6119 MGMT_OP_REMOVE_ADVERTISING,
6120 MGMT_STATUS_INVALID_PARAMS);
6121 goto unlock;
6122 }
6123
Arman Ugurayda9293352015-03-23 15:57:13 -07006124 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6125 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6126 pending_find(MGMT_OP_SET_LE, hdev)) {
6127 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6128 MGMT_STATUS_BUSY);
6129 goto unlock;
6130 }
6131
6132 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
6133 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6134 MGMT_STATUS_INVALID_PARAMS);
6135 goto unlock;
6136 }
6137
Florian Grandel01948332015-06-18 03:16:48 +02006138 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006139
Johan Hedbergf2252572015-11-18 12:49:20 +02006140 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006141
Florian Grandel01948332015-06-18 03:16:48 +02006142 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006143 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006144
Florian Grandel01948332015-06-18 03:16:48 +02006145 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6146 * flag is set or the device isn't powered then we have no HCI
6147 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006148 */
Florian Grandel01948332015-06-18 03:16:48 +02006149 if (skb_queue_empty(&req.cmd_q) ||
6150 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006151 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006152 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006153 err = mgmt_cmd_complete(sk, hdev->id,
6154 MGMT_OP_REMOVE_ADVERTISING,
6155 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6156 goto unlock;
6157 }
6158
6159 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6160 data_len);
6161 if (!cmd) {
6162 err = -ENOMEM;
6163 goto unlock;
6164 }
6165
Arman Ugurayda9293352015-03-23 15:57:13 -07006166 err = hci_req_run(&req, remove_advertising_complete);
6167 if (err < 0)
6168 mgmt_pending_remove(cmd);
6169
6170unlock:
6171 hci_dev_unlock(hdev);
6172
6173 return err;
6174}
6175
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006176static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6177{
6178 u8 max_len = HCI_MAX_AD_LENGTH;
6179
6180 if (is_adv_data) {
6181 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6182 MGMT_ADV_FLAG_LIMITED_DISCOV |
6183 MGMT_ADV_FLAG_MANAGED_FLAGS))
6184 max_len -= 3;
6185
6186 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6187 max_len -= 3;
6188 }
6189
6190 return max_len;
6191}
6192
6193static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6194 void *data, u16 data_len)
6195{
6196 struct mgmt_cp_get_adv_size_info *cp = data;
6197 struct mgmt_rp_get_adv_size_info rp;
6198 u32 flags, supported_flags;
6199 int err;
6200
6201 BT_DBG("%s", hdev->name);
6202
6203 if (!lmp_le_capable(hdev))
6204 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6205 MGMT_STATUS_REJECTED);
6206
6207 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6208 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6209 MGMT_STATUS_INVALID_PARAMS);
6210
6211 flags = __le32_to_cpu(cp->flags);
6212
6213 /* The current implementation only supports a subset of the specified
6214 * flags.
6215 */
6216 supported_flags = get_supported_adv_flags(hdev);
6217 if (flags & ~supported_flags)
6218 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6219 MGMT_STATUS_INVALID_PARAMS);
6220
6221 rp.instance = cp->instance;
6222 rp.flags = cp->flags;
6223 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6224 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6225
6226 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6227 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6228
6229 return err;
6230}
6231
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006232static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006233 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006234 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006235 HCI_MGMT_NO_HDEV |
6236 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006237 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006238 HCI_MGMT_NO_HDEV |
6239 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006240 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006241 HCI_MGMT_NO_HDEV |
6242 HCI_MGMT_UNTRUSTED },
6243 { read_controller_info, MGMT_READ_INFO_SIZE,
6244 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006245 { set_powered, MGMT_SETTING_SIZE },
6246 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6247 { set_connectable, MGMT_SETTING_SIZE },
6248 { set_fast_connectable, MGMT_SETTING_SIZE },
6249 { set_bondable, MGMT_SETTING_SIZE },
6250 { set_link_security, MGMT_SETTING_SIZE },
6251 { set_ssp, MGMT_SETTING_SIZE },
6252 { set_hs, MGMT_SETTING_SIZE },
6253 { set_le, MGMT_SETTING_SIZE },
6254 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6255 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6256 { add_uuid, MGMT_ADD_UUID_SIZE },
6257 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006258 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6259 HCI_MGMT_VAR_LEN },
6260 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6261 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006262 { disconnect, MGMT_DISCONNECT_SIZE },
6263 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6264 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6265 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6266 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6267 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6268 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6269 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6270 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6271 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6272 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6273 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006274 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6275 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6276 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006277 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6278 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6279 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6280 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6281 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6282 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6283 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6284 { set_advertising, MGMT_SETTING_SIZE },
6285 { set_bredr, MGMT_SETTING_SIZE },
6286 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6287 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6288 { set_secure_conn, MGMT_SETTING_SIZE },
6289 { set_debug_keys, MGMT_SETTING_SIZE },
6290 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006291 { load_irks, MGMT_LOAD_IRKS_SIZE,
6292 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006293 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6294 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6295 { add_device, MGMT_ADD_DEVICE_SIZE },
6296 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006297 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6298 HCI_MGMT_VAR_LEN },
6299 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006300 HCI_MGMT_NO_HDEV |
6301 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006302 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006303 HCI_MGMT_UNCONFIGURED |
6304 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006305 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6306 HCI_MGMT_UNCONFIGURED },
6307 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6308 HCI_MGMT_UNCONFIGURED },
6309 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6310 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006311 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006312 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006313 HCI_MGMT_NO_HDEV |
6314 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006315 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006316 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6317 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006318 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006319 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006320};
6321
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006322void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006323{
Marcel Holtmannced85542015-03-14 19:27:56 -07006324 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006325
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006326 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6327 return;
6328
Marcel Holtmannf9207332015-03-14 19:27:55 -07006329 switch (hdev->dev_type) {
6330 case HCI_BREDR:
6331 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6332 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6333 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006334 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006335 } else {
6336 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6337 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006338 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006339 }
6340 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006341 case HCI_AMP:
6342 ev.type = 0x02;
6343 break;
6344 default:
6345 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006346 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006347
6348 ev.bus = hdev->bus;
6349
6350 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6351 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006352}
6353
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006354void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006355{
Marcel Holtmannced85542015-03-14 19:27:56 -07006356 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006357 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006358
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006359 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6360 return;
6361
Marcel Holtmannf9207332015-03-14 19:27:55 -07006362 switch (hdev->dev_type) {
6363 case HCI_BREDR:
6364 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006365
Marcel Holtmannf9207332015-03-14 19:27:55 -07006366 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6367 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6368 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006369 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006370 } else {
6371 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6372 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006373 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006374 }
6375 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006376 case HCI_AMP:
6377 ev.type = 0x02;
6378 break;
6379 default:
6380 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006381 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006382
6383 ev.bus = hdev->bus;
6384
6385 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6386 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006387}
6388
Andre Guedes6046dc32014-02-26 20:21:51 -03006389/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006390static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006391{
6392 struct hci_conn_params *p;
6393
6394 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006395 /* Needed for AUTO_OFF case where might not "really"
6396 * have been powered off.
6397 */
6398 list_del_init(&p->action);
6399
6400 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006401 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006402 case HCI_AUTO_CONN_ALWAYS:
6403 list_add(&p->action, &hdev->pend_le_conns);
6404 break;
6405 case HCI_AUTO_CONN_REPORT:
6406 list_add(&p->action, &hdev->pend_le_reports);
6407 break;
6408 default:
6409 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006410 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006411 }
6412}
6413
Johan Hedberg2ff13892015-11-25 16:15:44 +02006414void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006415{
6416 struct cmd_lookup match = { NULL, hdev };
6417
Johan Hedberg2ff13892015-11-25 16:15:44 +02006418 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006419
Johan Hedberg2ff13892015-11-25 16:15:44 +02006420 hci_dev_lock(hdev);
6421
6422 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006423 restart_le_actions(hdev);
6424 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006425 }
6426
Johan Hedberg229ab392013-03-15 17:06:53 -05006427 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6428
6429 new_settings(hdev, match.sk);
6430
Johan Hedberg229ab392013-03-15 17:06:53 -05006431 if (match.sk)
6432 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006433
6434 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006435}
6436
Johan Hedberg2ff13892015-11-25 16:15:44 +02006437void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006438{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006439 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006440 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006441
Johan Hedberg229ab392013-03-15 17:06:53 -05006442 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006443
6444 /* If the power off is because of hdev unregistration let
6445 * use the appropriate INVALID_INDEX status. Otherwise use
6446 * NOT_POWERED. We cover both scenarios here since later in
6447 * mgmt_index_removed() any hci_conn callbacks will have already
6448 * been triggered, potentially causing misleading DISCONNECTED
6449 * status responses.
6450 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006451 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006452 status = MGMT_STATUS_INVALID_INDEX;
6453 else
6454 status = MGMT_STATUS_NOT_POWERED;
6455
6456 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006457
6458 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006459 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6460 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006461
Johan Hedberg2ff13892015-11-25 16:15:44 +02006462 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006463
6464 if (match.sk)
6465 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006466}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006467
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006468void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006469{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006470 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006471 u8 status;
6472
Johan Hedberg333ae952015-03-17 13:48:47 +02006473 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006474 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006475 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006476
6477 if (err == -ERFKILL)
6478 status = MGMT_STATUS_RFKILLED;
6479 else
6480 status = MGMT_STATUS_FAILED;
6481
Johan Hedberga69e8372015-03-06 21:08:53 +02006482 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006483
6484 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006485}
6486
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006487void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6488 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006489{
Johan Hedberg86742e12011-11-07 23:13:38 +02006490 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006491
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006492 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006493
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006494 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006495 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006496 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006497 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006498 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006499 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006500
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006501 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006502}
Johan Hedbergf7520542011-01-20 12:34:39 +02006503
Johan Hedbergd7b25452014-05-23 13:19:53 +03006504static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6505{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006506 switch (ltk->type) {
6507 case SMP_LTK:
6508 case SMP_LTK_SLAVE:
6509 if (ltk->authenticated)
6510 return MGMT_LTK_AUTHENTICATED;
6511 return MGMT_LTK_UNAUTHENTICATED;
6512 case SMP_LTK_P256:
6513 if (ltk->authenticated)
6514 return MGMT_LTK_P256_AUTH;
6515 return MGMT_LTK_P256_UNAUTH;
6516 case SMP_LTK_P256_DEBUG:
6517 return MGMT_LTK_P256_DEBUG;
6518 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006519
6520 return MGMT_LTK_UNAUTHENTICATED;
6521}
6522
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006523void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006524{
6525 struct mgmt_ev_new_long_term_key ev;
6526
6527 memset(&ev, 0, sizeof(ev));
6528
Marcel Holtmann5192d302014-02-19 17:11:58 -08006529 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006530 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006531 * to store long term keys. Their addresses will change the
6532 * next time around.
6533 *
6534 * Only when a remote device provides an identity address
6535 * make sure the long term key is stored. If the remote
6536 * identity is known, the long term keys are internally
6537 * mapped to the identity address. So allow static random
6538 * and public addresses here.
6539 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006540 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6541 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6542 ev.store_hint = 0x00;
6543 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006544 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006545
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006546 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006547 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006548 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006549 ev.key.enc_size = key->enc_size;
6550 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006551 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006552
Johan Hedberg2ceba532014-06-16 19:25:16 +03006553 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006554 ev.key.master = 1;
6555
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006556 /* Make sure we copy only the significant bytes based on the
6557 * encryption key size, and set the rest of the value to zeroes.
6558 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006559 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006560 memset(ev.key.val + key->enc_size, 0,
6561 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006562
Marcel Holtmann083368f2013-10-15 14:26:29 -07006563 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006564}
6565
Johan Hedbergcad20c22015-10-12 13:36:19 +02006566void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006567{
6568 struct mgmt_ev_new_irk ev;
6569
6570 memset(&ev, 0, sizeof(ev));
6571
Johan Hedbergcad20c22015-10-12 13:36:19 +02006572 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006573
Johan Hedberg95fbac82014-02-19 15:18:31 +02006574 bacpy(&ev.rpa, &irk->rpa);
6575 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6576 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6577 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6578
6579 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6580}
6581
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006582void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6583 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006584{
6585 struct mgmt_ev_new_csrk ev;
6586
6587 memset(&ev, 0, sizeof(ev));
6588
6589 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006590 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006591 * to store signature resolving keys. Their addresses will change
6592 * the next time around.
6593 *
6594 * Only when a remote device provides an identity address
6595 * make sure the signature resolving key is stored. So allow
6596 * static random and public addresses here.
6597 */
6598 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6599 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6600 ev.store_hint = 0x00;
6601 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006602 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006603
6604 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6605 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006606 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006607 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6608
6609 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6610}
6611
Andre Guedesffb5a8272014-07-01 18:10:11 -03006612void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006613 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6614 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006615{
6616 struct mgmt_ev_new_conn_param ev;
6617
Johan Hedbergc103aea2014-07-02 17:37:34 +03006618 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6619 return;
6620
Andre Guedesffb5a8272014-07-01 18:10:11 -03006621 memset(&ev, 0, sizeof(ev));
6622 bacpy(&ev.addr.bdaddr, bdaddr);
6623 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006624 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006625 ev.min_interval = cpu_to_le16(min_interval);
6626 ev.max_interval = cpu_to_le16(max_interval);
6627 ev.latency = cpu_to_le16(latency);
6628 ev.timeout = cpu_to_le16(timeout);
6629
6630 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6631}
6632
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006633void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6634 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006635{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006636 char buf[512];
6637 struct mgmt_ev_device_connected *ev = (void *) buf;
6638 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006639
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006640 bacpy(&ev->addr.bdaddr, &conn->dst);
6641 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006642
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006643 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006644
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006645 /* We must ensure that the EIR Data fields are ordered and
6646 * unique. Keep it simple for now and avoid the problem by not
6647 * adding any BR/EDR data to the LE adv.
6648 */
6649 if (conn->le_adv_data_len > 0) {
6650 memcpy(&ev->eir[eir_len],
6651 conn->le_adv_data, conn->le_adv_data_len);
6652 eir_len = conn->le_adv_data_len;
6653 } else {
6654 if (name_len > 0)
6655 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6656 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006657
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006658 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006659 eir_len = eir_append_data(ev->eir, eir_len,
6660 EIR_CLASS_OF_DEV,
6661 conn->dev_class, 3);
6662 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006663
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006664 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006665
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006666 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6667 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006668}
6669
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006670static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006671{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006672 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006673
Johan Hedbergf5818c22014-12-05 13:36:02 +02006674 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006675
6676 *sk = cmd->sk;
6677 sock_hold(*sk);
6678
Johan Hedberga664b5b2011-02-19 12:06:02 -03006679 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006680}
6681
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006682static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006683{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006684 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006685 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006686
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006687 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6688
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006689 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006690 mgmt_pending_remove(cmd);
6691}
6692
Johan Hedberg84c61d92014-08-01 11:13:30 +03006693bool mgmt_powering_down(struct hci_dev *hdev)
6694{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006695 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006696 struct mgmt_mode *cp;
6697
Johan Hedberg333ae952015-03-17 13:48:47 +02006698 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006699 if (!cmd)
6700 return false;
6701
6702 cp = cmd->param;
6703 if (!cp->val)
6704 return true;
6705
6706 return false;
6707}
6708
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006709void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006710 u8 link_type, u8 addr_type, u8 reason,
6711 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006712{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006713 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006714 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006715
Johan Hedberg84c61d92014-08-01 11:13:30 +03006716 /* The connection is still in hci_conn_hash so test for 1
6717 * instead of 0 to know if this is the last one.
6718 */
6719 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6720 cancel_delayed_work(&hdev->power_off);
6721 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006722 }
6723
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006724 if (!mgmt_connected)
6725 return;
6726
Andre Guedes57eb7762013-10-30 19:01:41 -03006727 if (link_type != ACL_LINK && link_type != LE_LINK)
6728 return;
6729
Johan Hedberg744cf192011-11-08 20:40:14 +02006730 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006731
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006732 bacpy(&ev.addr.bdaddr, bdaddr);
6733 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6734 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006735
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006736 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006737
6738 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006739 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006740
Johan Hedberg124f6e32012-02-09 13:50:12 +02006741 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006742 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006743}
6744
Marcel Holtmann78929242013-10-06 23:55:47 -07006745void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6746 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006747{
Andre Guedes3655bba2013-10-30 19:01:40 -03006748 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6749 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006750 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006751
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006752 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6753 hdev);
6754
Johan Hedberg333ae952015-03-17 13:48:47 +02006755 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006756 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006757 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006758
Andre Guedes3655bba2013-10-30 19:01:40 -03006759 cp = cmd->param;
6760
6761 if (bacmp(bdaddr, &cp->addr.bdaddr))
6762 return;
6763
6764 if (cp->addr.type != bdaddr_type)
6765 return;
6766
Johan Hedbergf5818c22014-12-05 13:36:02 +02006767 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006768 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006769}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006770
Marcel Holtmann445608d2013-10-06 23:55:48 -07006771void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6772 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006773{
6774 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006775
Johan Hedberg84c61d92014-08-01 11:13:30 +03006776 /* The connection is still in hci_conn_hash so test for 1
6777 * instead of 0 to know if this is the last one.
6778 */
6779 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6780 cancel_delayed_work(&hdev->power_off);
6781 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006782 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006783
Johan Hedberg4c659c32011-11-07 23:13:39 +02006784 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006785 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006786 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006787
Marcel Holtmann445608d2013-10-06 23:55:48 -07006788 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006789}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006790
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006791void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006792{
6793 struct mgmt_ev_pin_code_request ev;
6794
Johan Hedbergd8457692012-02-17 14:24:57 +02006795 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006796 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006797 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006798
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006799 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006800}
6801
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006802void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6803 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006804{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006805 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006806
Johan Hedberg333ae952015-03-17 13:48:47 +02006807 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006808 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006809 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006810
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006811 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006812 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006813}
6814
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006815void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6816 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006817{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006818 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006819
Johan Hedberg333ae952015-03-17 13:48:47 +02006820 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006821 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006822 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006823
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006824 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006825 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006826}
Johan Hedberga5c29682011-02-19 12:05:57 -03006827
Johan Hedberg744cf192011-11-08 20:40:14 +02006828int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006829 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006830 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006831{
6832 struct mgmt_ev_user_confirm_request ev;
6833
Johan Hedberg744cf192011-11-08 20:40:14 +02006834 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006835
Johan Hedberg272d90d2012-02-09 15:26:12 +02006836 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006837 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006838 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006839 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006840
Johan Hedberg744cf192011-11-08 20:40:14 +02006841 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006842 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006843}
6844
Johan Hedberg272d90d2012-02-09 15:26:12 +02006845int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006846 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08006847{
6848 struct mgmt_ev_user_passkey_request ev;
6849
6850 BT_DBG("%s", hdev->name);
6851
Johan Hedberg272d90d2012-02-09 15:26:12 +02006852 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006853 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08006854
6855 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006856 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08006857}
6858
Brian Gix0df4c182011-11-16 13:53:13 -08006859static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006860 u8 link_type, u8 addr_type, u8 status,
6861 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03006862{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006863 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03006864
Johan Hedberg333ae952015-03-17 13:48:47 +02006865 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03006866 if (!cmd)
6867 return -ENOENT;
6868
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006869 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006870 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03006871
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006872 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03006873}
6874
Johan Hedberg744cf192011-11-08 20:40:14 +02006875int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006876 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006877{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006878 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006879 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006880}
6881
Johan Hedberg272d90d2012-02-09 15:26:12 +02006882int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006883 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006884{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006885 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006886 status,
6887 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006888}
Johan Hedberg2a611692011-02-19 12:06:00 -03006889
Brian Gix604086b2011-11-23 08:28:33 -08006890int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006891 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006892{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006893 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006894 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006895}
6896
Johan Hedberg272d90d2012-02-09 15:26:12 +02006897int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006898 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006899{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006900 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006901 status,
6902 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006903}
6904
Johan Hedberg92a25252012-09-06 18:39:26 +03006905int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
6906 u8 link_type, u8 addr_type, u32 passkey,
6907 u8 entered)
6908{
6909 struct mgmt_ev_passkey_notify ev;
6910
6911 BT_DBG("%s", hdev->name);
6912
6913 bacpy(&ev.addr.bdaddr, bdaddr);
6914 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6915 ev.passkey = __cpu_to_le32(passkey);
6916 ev.entered = entered;
6917
6918 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
6919}
6920
Johan Hedberge1e930f2014-09-08 17:09:49 -07006921void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03006922{
6923 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006924 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07006925 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03006926
Johan Hedberge1e930f2014-09-08 17:09:49 -07006927 bacpy(&ev.addr.bdaddr, &conn->dst);
6928 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
6929 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03006930
Johan Hedberge1e930f2014-09-08 17:09:49 -07006931 cmd = find_pairing(conn);
6932
6933 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
6934 cmd ? cmd->sk : NULL);
6935
Johan Hedberga511b352014-12-11 21:45:45 +02006936 if (cmd) {
6937 cmd->cmd_complete(cmd, status);
6938 mgmt_pending_remove(cmd);
6939 }
Johan Hedberg2a611692011-02-19 12:06:00 -03006940}
Johan Hedbergb312b1612011-03-16 14:29:37 +02006941
Marcel Holtmann464996a2013-10-15 14:26:24 -07006942void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006943{
6944 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07006945 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006946
6947 if (status) {
6948 u8 mgmt_err = mgmt_status(status);
6949 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006950 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07006951 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006952 }
6953
Marcel Holtmann464996a2013-10-15 14:26:24 -07006954 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07006955 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07006956 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006957 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02006958
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006959 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006960 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006961
Johan Hedberg47990ea2012-02-22 11:58:37 +02006962 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07006963 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006964
6965 if (match.sk)
6966 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006967}
6968
Johan Hedberg890ea892013-03-15 17:06:52 -05006969static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02006970{
Johan Hedberg890ea892013-03-15 17:06:52 -05006971 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02006972 struct hci_cp_write_eir cp;
6973
Johan Hedberg976eb202012-10-24 21:12:01 +03006974 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006975 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02006976
Johan Hedbergc80da272012-02-22 15:38:48 +02006977 memset(hdev->eir, 0, sizeof(hdev->eir));
6978
Johan Hedbergcacaf522012-02-21 00:52:42 +02006979 memset(&cp, 0, sizeof(cp));
6980
Johan Hedberg890ea892013-03-15 17:06:52 -05006981 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02006982}
6983
Marcel Holtmann3e248562013-10-15 14:26:25 -07006984void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02006985{
6986 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05006987 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02006988 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02006989
6990 if (status) {
6991 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02006992
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006993 if (enable && hci_dev_test_and_clear_flag(hdev,
6994 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006995 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07006996 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07006997 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02006998
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006999 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7000 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007001 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007002 }
7003
7004 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007005 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007006 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007007 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007008 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007009 changed = hci_dev_test_and_clear_flag(hdev,
7010 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007011 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007012 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007013 }
7014
7015 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7016
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007017 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007018 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007019
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007020 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007021 sock_put(match.sk);
7022
Johan Hedberg890ea892013-03-15 17:06:52 -05007023 hci_req_init(&req, hdev);
7024
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007025 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7026 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007027 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7028 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007029 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007030 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007031 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007032 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007033
7034 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007035}
7036
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007037static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007038{
7039 struct cmd_lookup *match = data;
7040
Johan Hedberg90e70452012-02-23 23:09:40 +02007041 if (match->sk == NULL) {
7042 match->sk = cmd->sk;
7043 sock_hold(match->sk);
7044 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007045}
7046
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007047void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7048 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007049{
Johan Hedberg90e70452012-02-23 23:09:40 +02007050 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007051
Johan Hedberg92da6092013-03-15 17:06:55 -05007052 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7053 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7054 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007055
7056 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007057 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7058 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007059
7060 if (match.sk)
7061 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007062}
7063
Marcel Holtmann7667da32013-10-15 14:26:27 -07007064void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007065{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007066 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007067 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007068
Johan Hedberg13928972013-03-15 17:07:00 -05007069 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007070 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007071
7072 memset(&ev, 0, sizeof(ev));
7073 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007074 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007075
Johan Hedberg333ae952015-03-17 13:48:47 +02007076 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007077 if (!cmd) {
7078 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007079
Johan Hedberg13928972013-03-15 17:07:00 -05007080 /* If this is a HCI command related to powering on the
7081 * HCI dev don't send any mgmt signals.
7082 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007083 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007084 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007085 }
7086
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007087 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7088 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007089}
Szymon Jancc35938b2011-03-22 13:12:21 +01007090
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007091static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7092{
7093 int i;
7094
7095 for (i = 0; i < uuid_count; i++) {
7096 if (!memcmp(uuid, uuids[i], 16))
7097 return true;
7098 }
7099
7100 return false;
7101}
7102
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007103static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7104{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007105 u16 parsed = 0;
7106
7107 while (parsed < eir_len) {
7108 u8 field_len = eir[0];
7109 u8 uuid[16];
7110 int i;
7111
7112 if (field_len == 0)
7113 break;
7114
7115 if (eir_len - parsed < field_len + 1)
7116 break;
7117
7118 switch (eir[1]) {
7119 case EIR_UUID16_ALL:
7120 case EIR_UUID16_SOME:
7121 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007122 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007123 uuid[13] = eir[i + 3];
7124 uuid[12] = eir[i + 2];
7125 if (has_uuid(uuid, uuid_count, uuids))
7126 return true;
7127 }
7128 break;
7129 case EIR_UUID32_ALL:
7130 case EIR_UUID32_SOME:
7131 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007132 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007133 uuid[15] = eir[i + 5];
7134 uuid[14] = eir[i + 4];
7135 uuid[13] = eir[i + 3];
7136 uuid[12] = eir[i + 2];
7137 if (has_uuid(uuid, uuid_count, uuids))
7138 return true;
7139 }
7140 break;
7141 case EIR_UUID128_ALL:
7142 case EIR_UUID128_SOME:
7143 for (i = 0; i + 17 <= field_len; i += 16) {
7144 memcpy(uuid, eir + i + 2, 16);
7145 if (has_uuid(uuid, uuid_count, uuids))
7146 return true;
7147 }
7148 break;
7149 }
7150
7151 parsed += field_len + 1;
7152 eir += field_len + 1;
7153 }
7154
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007155 return false;
7156}
7157
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007158static void restart_le_scan(struct hci_dev *hdev)
7159{
7160 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007161 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007162 return;
7163
7164 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7165 hdev->discovery.scan_start +
7166 hdev->discovery.scan_duration))
7167 return;
7168
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007169 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007170 DISCOV_LE_RESTART_DELAY);
7171}
7172
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007173static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7174 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7175{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007176 /* If a RSSI threshold has been specified, and
7177 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7178 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7179 * is set, let it through for further processing, as we might need to
7180 * restart the scan.
7181 *
7182 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7183 * the results are also dropped.
7184 */
7185 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7186 (rssi == HCI_RSSI_INVALID ||
7187 (rssi < hdev->discovery.rssi &&
7188 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7189 return false;
7190
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007191 if (hdev->discovery.uuid_count != 0) {
7192 /* If a list of UUIDs is provided in filter, results with no
7193 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007194 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007195 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7196 hdev->discovery.uuids) &&
7197 !eir_has_uuids(scan_rsp, scan_rsp_len,
7198 hdev->discovery.uuid_count,
7199 hdev->discovery.uuids))
7200 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007201 }
7202
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007203 /* If duplicate filtering does not report RSSI changes, then restart
7204 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007205 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007206 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7207 restart_le_scan(hdev);
7208
7209 /* Validate RSSI value against the RSSI threshold once more. */
7210 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7211 rssi < hdev->discovery.rssi)
7212 return false;
7213 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007214
7215 return true;
7216}
7217
Marcel Holtmann901801b2013-10-06 23:55:51 -07007218void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007219 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7220 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007221{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007222 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007223 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007224 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007225
Johan Hedberg75ce2082014-07-02 22:42:01 +03007226 /* Don't send events for a non-kernel initiated discovery. With
7227 * LE one exception is if we have pend_le_reports > 0 in which
7228 * case we're doing passive scanning and want these events.
7229 */
7230 if (!hci_discovery_active(hdev)) {
7231 if (link_type == ACL_LINK)
7232 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007233 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007234 return;
7235 }
Andre Guedes12602d02013-04-30 15:29:40 -03007236
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007237 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007238 /* We are using service discovery */
7239 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7240 scan_rsp_len))
7241 return;
7242 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007243
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007244 /* Make sure that the buffer is big enough. The 5 extra bytes
7245 * are for the potential CoD field.
7246 */
7247 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007248 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007249
Johan Hedberg1dc06092012-01-15 21:01:23 +02007250 memset(buf, 0, sizeof(buf));
7251
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007252 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7253 * RSSI value was reported as 0 when not available. This behavior
7254 * is kept when using device discovery. This is required for full
7255 * backwards compatibility with the API.
7256 *
7257 * However when using service discovery, the value 127 will be
7258 * returned when the RSSI is not available.
7259 */
Szymon Janc91200e92015-01-22 16:57:05 +01007260 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7261 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007262 rssi = 0;
7263
Johan Hedberg841c5642014-07-07 12:45:54 +03007264 bacpy(&ev->addr.bdaddr, bdaddr);
7265 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007266 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007267 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007268
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007269 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007270 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007271 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007272
Johan Hedberg1dc06092012-01-15 21:01:23 +02007273 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7274 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007275 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007276
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007277 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007278 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007279 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007280
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007281 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7282 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007283
Marcel Holtmann901801b2013-10-06 23:55:51 -07007284 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007285}
Johan Hedberga88a9652011-03-30 13:18:12 +03007286
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007287void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7288 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007289{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007290 struct mgmt_ev_device_found *ev;
7291 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7292 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007293
Johan Hedbergb644ba32012-01-17 21:48:47 +02007294 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007295
Johan Hedbergb644ba32012-01-17 21:48:47 +02007296 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007297
Johan Hedbergb644ba32012-01-17 21:48:47 +02007298 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007299 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007300 ev->rssi = rssi;
7301
7302 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007303 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007304
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007305 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007306
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007307 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007308}
Johan Hedberg314b2382011-04-27 10:29:57 -04007309
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007310void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007311{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007312 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007313
Andre Guedes343fb142011-11-22 17:14:19 -03007314 BT_DBG("%s discovering %u", hdev->name, discovering);
7315
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007316 memset(&ev, 0, sizeof(ev));
7317 ev.type = hdev->discovery.type;
7318 ev.discovering = discovering;
7319
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007320 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007321}
Antti Julku5e762442011-08-25 16:48:02 +03007322
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007323static struct hci_mgmt_chan chan = {
7324 .channel = HCI_CHANNEL_CONTROL,
7325 .handler_count = ARRAY_SIZE(mgmt_handlers),
7326 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007327 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007328};
7329
7330int mgmt_init(void)
7331{
7332 return hci_mgmt_chan_register(&chan);
7333}
7334
7335void mgmt_exit(void)
7336{
7337 hci_mgmt_chan_unregister(&chan);
7338}