blob: 3297a4ecc05ecd4e7ecbce29047a2c1d38992447 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Johan Hedbergdc4270c2015-11-23 15:07:51 +020041#define MGMT_REVISION 11
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
108static const u16 mgmt_events[] = {
109 MGMT_EV_CONTROLLER_ERROR,
110 MGMT_EV_INDEX_ADDED,
111 MGMT_EV_INDEX_REMOVED,
112 MGMT_EV_NEW_SETTINGS,
113 MGMT_EV_CLASS_OF_DEV_CHANGED,
114 MGMT_EV_LOCAL_NAME_CHANGED,
115 MGMT_EV_NEW_LINK_KEY,
116 MGMT_EV_NEW_LONG_TERM_KEY,
117 MGMT_EV_DEVICE_CONNECTED,
118 MGMT_EV_DEVICE_DISCONNECTED,
119 MGMT_EV_CONNECT_FAILED,
120 MGMT_EV_PIN_CODE_REQUEST,
121 MGMT_EV_USER_CONFIRM_REQUEST,
122 MGMT_EV_USER_PASSKEY_REQUEST,
123 MGMT_EV_AUTH_FAILED,
124 MGMT_EV_DEVICE_FOUND,
125 MGMT_EV_DISCOVERING,
126 MGMT_EV_DEVICE_BLOCKED,
127 MGMT_EV_DEVICE_UNBLOCKED,
128 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300129 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800130 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700131 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200132 MGMT_EV_DEVICE_ADDED,
133 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300134 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200135 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200136 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200137 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700138 MGMT_EV_EXT_INDEX_ADDED,
139 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700140 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700141 MGMT_EV_ADVERTISING_ADDED,
142 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200143};
144
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700145static const u16 mgmt_untrusted_commands[] = {
146 MGMT_OP_READ_INDEX_LIST,
147 MGMT_OP_READ_INFO,
148 MGMT_OP_READ_UNCONF_INDEX_LIST,
149 MGMT_OP_READ_CONFIG_INFO,
150 MGMT_OP_READ_EXT_INDEX_LIST,
151};
152
153static const u16 mgmt_untrusted_events[] = {
154 MGMT_EV_INDEX_ADDED,
155 MGMT_EV_INDEX_REMOVED,
156 MGMT_EV_NEW_SETTINGS,
157 MGMT_EV_CLASS_OF_DEV_CHANGED,
158 MGMT_EV_LOCAL_NAME_CHANGED,
159 MGMT_EV_UNCONF_INDEX_ADDED,
160 MGMT_EV_UNCONF_INDEX_REMOVED,
161 MGMT_EV_NEW_CONFIG_OPTIONS,
162 MGMT_EV_EXT_INDEX_ADDED,
163 MGMT_EV_EXT_INDEX_REMOVED,
164};
165
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800166#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200167
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200168#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
169 "\x00\x00\x00\x00\x00\x00\x00\x00"
170
Johan Hedbergca69b792011-11-11 18:10:00 +0200171/* HCI to MGMT error code conversion table */
172static u8 mgmt_status_table[] = {
173 MGMT_STATUS_SUCCESS,
174 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
175 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
176 MGMT_STATUS_FAILED, /* Hardware Failure */
177 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
178 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200179 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200180 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
181 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
182 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
184 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
185 MGMT_STATUS_BUSY, /* Command Disallowed */
186 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
187 MGMT_STATUS_REJECTED, /* Rejected Security */
188 MGMT_STATUS_REJECTED, /* Rejected Personal */
189 MGMT_STATUS_TIMEOUT, /* Host Timeout */
190 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
191 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
192 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
193 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
194 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
195 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
196 MGMT_STATUS_BUSY, /* Repeated Attempts */
197 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
198 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
199 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
200 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
201 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
202 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
203 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
204 MGMT_STATUS_FAILED, /* Unspecified Error */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
206 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
207 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
208 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
209 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
210 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
211 MGMT_STATUS_FAILED, /* Unit Link Key Used */
212 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
213 MGMT_STATUS_TIMEOUT, /* Instant Passed */
214 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
215 MGMT_STATUS_FAILED, /* Transaction Collision */
216 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
217 MGMT_STATUS_REJECTED, /* QoS Rejected */
218 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
219 MGMT_STATUS_REJECTED, /* Insufficient Security */
220 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
221 MGMT_STATUS_BUSY, /* Role Switch Pending */
222 MGMT_STATUS_FAILED, /* Slot Violation */
223 MGMT_STATUS_FAILED, /* Role Switch Failed */
224 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
225 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
226 MGMT_STATUS_BUSY, /* Host Busy Pairing */
227 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
228 MGMT_STATUS_BUSY, /* Controller Busy */
229 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
230 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
231 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
232 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
233 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
234};
235
236static u8 mgmt_status(u8 hci_status)
237{
238 if (hci_status < ARRAY_SIZE(mgmt_status_table))
239 return mgmt_status_table[hci_status];
240
241 return MGMT_STATUS_FAILED;
242}
243
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700244static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
245 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700246{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700247 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
248 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700249}
250
Marcel Holtmann72000df2015-03-16 16:11:21 -0700251static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
252 u16 len, int flag, struct sock *skip_sk)
253{
254 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
255 flag, skip_sk);
256}
257
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700258static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
259 u16 len, struct sock *skip_sk)
260{
261 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
262 HCI_MGMT_GENERIC_EVENTS, skip_sk);
263}
264
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200265static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
266 struct sock *skip_sk)
267{
268 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700269 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200270}
271
Johan Hedberg85813a72015-10-21 18:02:59 +0300272static u8 le_addr_type(u8 mgmt_addr_type)
273{
274 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
275 return ADDR_LE_DEV_PUBLIC;
276 else
277 return ADDR_LE_DEV_RANDOM;
278}
279
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300280static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
281 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200282{
283 struct mgmt_rp_read_version rp;
284
285 BT_DBG("sock %p", sk);
286
287 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700288 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200289
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200290 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
291 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200292}
293
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300294static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
295 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296{
297 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700298 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200299 size_t rp_size;
300 int i, err;
301
302 BT_DBG("sock %p", sk);
303
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
305 num_commands = ARRAY_SIZE(mgmt_commands);
306 num_events = ARRAY_SIZE(mgmt_events);
307 } else {
308 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
309 num_events = ARRAY_SIZE(mgmt_untrusted_events);
310 }
311
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
313
314 rp = kmalloc(rp_size, GFP_KERNEL);
315 if (!rp)
316 return -ENOMEM;
317
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700318 rp->num_commands = cpu_to_le16(num_commands);
319 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700321 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
322 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200323
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700324 for (i = 0; i < num_commands; i++, opcode++)
325 put_unaligned_le16(mgmt_commands[i], opcode);
326
327 for (i = 0; i < num_events; i++, opcode++)
328 put_unaligned_le16(mgmt_events[i], opcode);
329 } else {
330 __le16 *opcode = rp->opcodes;
331
332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
337 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200338
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200339 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
340 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200341 kfree(rp);
342
343 return err;
344}
345
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300346static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
347 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200351 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
355 BT_DBG("sock %p", sk);
356
357 read_lock(&hci_dev_list_lock);
358
359 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300360 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200361 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700362 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700363 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364 }
365
Johan Hedberga38528f2011-01-22 06:46:43 +0200366 rp_len = sizeof(*rp) + (2 * count);
367 rp = kmalloc(rp_len, GFP_ATOMIC);
368 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100369 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100371 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372
Johan Hedberg476e44c2012-10-19 20:10:46 +0300373 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200374 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700375 if (hci_dev_test_flag(d, HCI_SETUP) ||
376 hci_dev_test_flag(d, HCI_CONFIG) ||
377 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200378 continue;
379
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200380 /* Devices marked as raw-only are neither configured
381 * nor unconfigured controllers.
382 */
383 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700387 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700388 rp->index[count++] = cpu_to_le16(d->id);
389 BT_DBG("Added hci%u", d->id);
390 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391 }
392
Johan Hedberg476e44c2012-10-19 20:10:46 +0300393 rp->num_controllers = cpu_to_le16(count);
394 rp_len = sizeof(*rp) + (2 * count);
395
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 read_unlock(&hci_dev_list_lock);
397
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200398 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
399 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400
Johan Hedberga38528f2011-01-22 06:46:43 +0200401 kfree(rp);
402
403 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404}
405
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200406static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
407 void *data, u16 data_len)
408{
409 struct mgmt_rp_read_unconf_index_list *rp;
410 struct hci_dev *d;
411 size_t rp_len;
412 u16 count;
413 int err;
414
415 BT_DBG("sock %p", sk);
416
417 read_lock(&hci_dev_list_lock);
418
419 count = 0;
420 list_for_each_entry(d, &hci_dev_list, list) {
421 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700422 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200423 count++;
424 }
425
426 rp_len = sizeof(*rp) + (2 * count);
427 rp = kmalloc(rp_len, GFP_ATOMIC);
428 if (!rp) {
429 read_unlock(&hci_dev_list_lock);
430 return -ENOMEM;
431 }
432
433 count = 0;
434 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700435 if (hci_dev_test_flag(d, HCI_SETUP) ||
436 hci_dev_test_flag(d, HCI_CONFIG) ||
437 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438 continue;
439
440 /* Devices marked as raw-only are neither configured
441 * nor unconfigured controllers.
442 */
443 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
444 continue;
445
446 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700447 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448 rp->index[count++] = cpu_to_le16(d->id);
449 BT_DBG("Added hci%u", d->id);
450 }
451 }
452
453 rp->num_controllers = cpu_to_le16(count);
454 rp_len = sizeof(*rp) + (2 * count);
455
456 read_unlock(&hci_dev_list_lock);
457
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200458 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
459 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200460
461 kfree(rp);
462
463 return err;
464}
465
Marcel Holtmann96f14742015-03-14 19:27:57 -0700466static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
467 void *data, u16 data_len)
468{
469 struct mgmt_rp_read_ext_index_list *rp;
470 struct hci_dev *d;
471 size_t rp_len;
472 u16 count;
473 int err;
474
475 BT_DBG("sock %p", sk);
476
477 read_lock(&hci_dev_list_lock);
478
479 count = 0;
480 list_for_each_entry(d, &hci_dev_list, list) {
481 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
482 count++;
483 }
484
485 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
486 rp = kmalloc(rp_len, GFP_ATOMIC);
487 if (!rp) {
488 read_unlock(&hci_dev_list_lock);
489 return -ENOMEM;
490 }
491
492 count = 0;
493 list_for_each_entry(d, &hci_dev_list, list) {
494 if (hci_dev_test_flag(d, HCI_SETUP) ||
495 hci_dev_test_flag(d, HCI_CONFIG) ||
496 hci_dev_test_flag(d, HCI_USER_CHANNEL))
497 continue;
498
499 /* Devices marked as raw-only are neither configured
500 * nor unconfigured controllers.
501 */
502 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
503 continue;
504
505 if (d->dev_type == HCI_BREDR) {
506 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
507 rp->entry[count].type = 0x01;
508 else
509 rp->entry[count].type = 0x00;
510 } else if (d->dev_type == HCI_AMP) {
511 rp->entry[count].type = 0x02;
512 } else {
513 continue;
514 }
515
516 rp->entry[count].bus = d->bus;
517 rp->entry[count++].index = cpu_to_le16(d->id);
518 BT_DBG("Added hci%u", d->id);
519 }
520
521 rp->num_controllers = cpu_to_le16(count);
522 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
523
524 read_unlock(&hci_dev_list_lock);
525
526 /* If this command is called at least once, then all the
527 * default index and unconfigured index events are disabled
528 * and from now on only extended index events are used.
529 */
530 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
531 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
532 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
533
534 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
535 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
536
537 kfree(rp);
538
539 return err;
540}
541
Marcel Holtmanndbece372014-07-04 18:11:55 +0200542static bool is_configured(struct hci_dev *hdev)
543{
544 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700545 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200546 return false;
547
548 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
549 !bacmp(&hdev->public_addr, BDADDR_ANY))
550 return false;
551
552 return true;
553}
554
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200555static __le32 get_missing_options(struct hci_dev *hdev)
556{
557 u32 options = 0;
558
Marcel Holtmanndbece372014-07-04 18:11:55 +0200559 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700560 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200561 options |= MGMT_OPTION_EXTERNAL_CONFIG;
562
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200563 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
564 !bacmp(&hdev->public_addr, BDADDR_ANY))
565 options |= MGMT_OPTION_PUBLIC_ADDRESS;
566
567 return cpu_to_le32(options);
568}
569
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200570static int new_options(struct hci_dev *hdev, struct sock *skip)
571{
572 __le32 options = get_missing_options(hdev);
573
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700574 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
575 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576}
577
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
579{
580 __le32 options = get_missing_options(hdev);
581
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200582 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
583 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584}
585
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200586static int read_config_info(struct sock *sk, struct hci_dev *hdev,
587 void *data, u16 data_len)
588{
589 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200590 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591
592 BT_DBG("sock %p %s", sk, hdev->name);
593
594 hci_dev_lock(hdev);
595
596 memset(&rp, 0, sizeof(rp));
597 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
600 options |= MGMT_OPTION_EXTERNAL_CONFIG;
601
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200602 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603 options |= MGMT_OPTION_PUBLIC_ADDRESS;
604
605 rp.supported_options = cpu_to_le32(options);
606 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607
608 hci_dev_unlock(hdev);
609
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
611 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612}
613
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200614static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200615{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200617
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300619 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800620 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300621 settings |= MGMT_SETTING_CONNECTABLE;
622 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Andre Guedesed3fa312012-07-24 15:03:46 -0300624 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500625 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
626 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627 settings |= MGMT_SETTING_BREDR;
628 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700629
630 if (lmp_ssp_capable(hdev)) {
631 settings |= MGMT_SETTING_SSP;
632 settings |= MGMT_SETTING_HS;
633 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800634
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800635 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800636 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700637 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100638
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300639 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200640 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300641 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300642 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200643 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800644 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300645 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200646
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200647 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
648 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200649 settings |= MGMT_SETTING_CONFIGURATION;
650
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651 return settings;
652}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200653
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200654static u32 get_current_settings(struct hci_dev *hdev)
655{
656 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200657
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200658 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100659 settings |= MGMT_SETTING_POWERED;
660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662 settings |= MGMT_SETTING_CONNECTABLE;
663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700664 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500665 settings |= MGMT_SETTING_FAST_CONNECTABLE;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_DISCOVERABLE;
669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300671 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_BREDR;
675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200683 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200686 settings |= MGMT_SETTING_HS;
687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300689 settings |= MGMT_SETTING_ADVERTISING;
690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700691 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800692 settings |= MGMT_SETTING_SECURE_CONN;
693
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700694 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800695 settings |= MGMT_SETTING_DEBUG_KEYS;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200698 settings |= MGMT_SETTING_PRIVACY;
699
Marcel Holtmann93690c22015-03-06 10:11:21 -0800700 /* The current setting for static address has two purposes. The
701 * first is to indicate if the static address will be used and
702 * the second is to indicate if it is actually set.
703 *
704 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700705 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800706 * address is actually used decides if the flag is set or not.
707 *
708 * For single mode LE only controllers and dual-mode controllers
709 * with BR/EDR disabled, the existence of the static address will
710 * be evaluated.
711 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700712 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700713 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800714 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
715 if (bacmp(&hdev->static_addr, BDADDR_ANY))
716 settings |= MGMT_SETTING_STATIC_ADDRESS;
717 }
718
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200720}
721
Johan Hedberg333ae952015-03-17 13:48:47 +0200722static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
723{
724 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
725}
726
Johan Hedberg333ae952015-03-17 13:48:47 +0200727static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
728 struct hci_dev *hdev,
729 const void *data)
730{
731 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
732}
733
Johan Hedbergf2252572015-11-18 12:49:20 +0200734u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300735{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200736 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300737
738 /* If there's a pending mgmt command the flags will not yet have
739 * their final values, so check for this first.
740 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200741 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300742 if (cmd) {
743 struct mgmt_mode *cp = cmd->param;
744 if (cp->val == 0x01)
745 return LE_AD_GENERAL;
746 else if (cp->val == 0x02)
747 return LE_AD_LIMITED;
748 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700749 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300750 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700751 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300752 return LE_AD_GENERAL;
753 }
754
755 return 0;
756}
757
Johan Hedbergf2252572015-11-18 12:49:20 +0200758bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700759{
760 struct mgmt_pending_cmd *cmd;
761
762 /* If there's a pending mgmt command the flag will not yet have
763 * it's final value, so check for this first.
764 */
765 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
766 if (cmd) {
767 struct mgmt_mode *cp = cmd->param;
768
769 return cp->val;
770 }
771
772 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
773}
774
Johan Hedberg7d785252011-12-15 00:47:39 +0200775static void service_cache_off(struct work_struct *work)
776{
777 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300778 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500779 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200780
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700781 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200782 return;
783
Johan Hedberg890ea892013-03-15 17:06:52 -0500784 hci_req_init(&req, hdev);
785
Johan Hedberg7d785252011-12-15 00:47:39 +0200786 hci_dev_lock(hdev);
787
Johan Hedbergb1a89172015-11-25 16:15:42 +0200788 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200789 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200790
791 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500792
793 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200794}
795
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200796static void rpa_expired(struct work_struct *work)
797{
798 struct hci_dev *hdev = container_of(work, struct hci_dev,
799 rpa_expired.work);
800 struct hci_request req;
801
802 BT_DBG("");
803
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700804 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200805
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700806 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200807 return;
808
809 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200810 * controller happens in the hci_req_enable_advertising()
811 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200812 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200813 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +0200814 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200815 hci_req_run(&req, NULL);
816}
817
Johan Hedberg6a919082012-02-28 06:17:26 +0200818static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200819{
Marcel Holtmann238be782015-03-13 02:11:06 -0700820 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200821 return;
822
Johan Hedberg4f87da82012-03-02 19:55:56 +0200823 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200824 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200825
Johan Hedberg4f87da82012-03-02 19:55:56 +0200826 /* Non-mgmt controlled devices get this bit set
827 * implicitly so that pairing works for them, however
828 * for mgmt we require user-space to explicitly enable
829 * it
830 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700831 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200832}
833
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200834static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300835 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
837 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200838
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200839 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200840
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300841 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Johan Hedberg03811012010-12-08 00:21:06 +0200843 memset(&rp, 0, sizeof(rp));
844
Johan Hedberg03811012010-12-08 00:21:06 +0200845 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200846
847 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200848 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200849
850 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
851 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
852
853 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200854
855 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200856 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300858 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200859
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200860 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
861 sizeof(rp));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862}
863
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200864static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200865{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200866 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200867
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200868 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
869 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200870}
871
Marcel Holtmann1904a852015-01-11 13:50:44 -0800872static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200873{
874 BT_DBG("%s status 0x%02x", hdev->name, status);
875
Johan Hedberga3172b72014-02-28 09:33:44 +0200876 if (hci_conn_count(hdev) == 0) {
877 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200878 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200879 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200880}
881
Johan Hedbergf2252572015-11-18 12:49:20 +0200882void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700883{
884 struct mgmt_ev_advertising_added ev;
885
886 ev.instance = instance;
887
888 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
889}
890
Johan Hedbergf2252572015-11-18 12:49:20 +0200891void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
892 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700893{
894 struct mgmt_ev_advertising_removed ev;
895
896 ev.instance = instance;
897
898 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
899}
900
Florian Grandel7816b822015-06-18 03:16:45 +0200901static void cancel_adv_timeout(struct hci_dev *hdev)
902{
903 if (hdev->adv_instance_timeout) {
904 hdev->adv_instance_timeout = 0;
905 cancel_delayed_work(&hdev->adv_instance_expire);
906 }
907}
908
Johan Hedberg8b064a32014-02-24 14:52:22 +0200909static int clean_up_hci_state(struct hci_dev *hdev)
910{
911 struct hci_request req;
912 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300913 bool discov_stopped;
914 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200915
916 hci_req_init(&req, hdev);
917
918 if (test_bit(HCI_ISCAN, &hdev->flags) ||
919 test_bit(HCI_PSCAN, &hdev->flags)) {
920 u8 scan = 0x00;
921 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
922 }
923
Johan Hedbergf2252572015-11-18 12:49:20 +0200924 hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -0700925
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700926 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +0200927 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200928
Johan Hedberg2154d3f2015-11-11 08:30:45 +0200929 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200930
931 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +0300932 /* 0x15 == Terminated due to Power Off */
933 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200934 }
935
Johan Hedberg23a48092014-07-08 16:05:06 +0300936 err = hci_req_run(&req, clean_up_hci_complete);
937 if (!err && discov_stopped)
938 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
939
940 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200941}
942
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200943static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200945{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300946 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200947 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200948 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200950 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Johan Hedberga7e80f22013-01-09 16:05:19 +0200952 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +0200953 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
954 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +0200955
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300956 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200957
Johan Hedberg333ae952015-03-17 13:48:47 +0200958 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +0200959 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
960 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300961 goto failed;
962 }
963
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 Hedberge8ba3a12013-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 Hedberge8ba3a12013-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 Hedberge8ba3a12013-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 Hedberge8ba3a12013-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 Hedberge8ba3a12013-10-19 23:38:18 +03001297 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001298 }
Johan Hedberge8ba3a12013-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 Hedberge8ba3a12013-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 Hedbergcab054a2015-11-30 11:21:45 +02001629 __hci_req_update_adv_data(&req, 0x00);
1630 __hci_req_update_scan_rsp_data(&req, 0x00);
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 Hedbergcab054a2015-11-30 11:21:45 +02003009 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
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 Hedberg81328d52014-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 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003738 goto unlock;
3739
Florian Grandel7816b822015-06-18 03:16:45 +02003740 instance = hdev->cur_adv_instance;
3741 if (!instance) {
3742 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3743 struct adv_info, list);
3744 if (!adv_instance)
3745 goto unlock;
3746
3747 instance = adv_instance->instance;
3748 }
3749
Arman Uguray24b4f382015-03-23 15:57:12 -07003750 hci_req_init(&req, hdev);
3751
Johan Hedbergf2252572015-11-18 12:49:20 +02003752 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003753
Florian Grandel7816b822015-06-18 03:16:45 +02003754 if (!err)
3755 err = hci_req_run(&req, enable_advertising_instance);
3756
3757 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003758 BT_ERR("Failed to re-configure advertising");
3759
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303760unlock:
3761 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003762}
3763
Marcel Holtmann21b51872013-10-10 09:47:53 -07003764static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3765 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003766{
3767 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003768 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003769 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003770 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003771 int err;
3772
3773 BT_DBG("request for %s", hdev->name);
3774
Johan Hedberge6fe7982013-10-02 15:45:22 +03003775 status = mgmt_le_support(hdev);
3776 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003777 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3778 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003779
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003780 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003781 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3782 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003783
3784 hci_dev_lock(hdev);
3785
3786 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003787
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003788 /* The following conditions are ones which mean that we should
3789 * not do any HCI communication but directly send a mgmt
3790 * response to user space (after toggling the flag if
3791 * necessary).
3792 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003793 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003794 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3795 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003796 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003797 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003798 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003799 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003800
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003801 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003802 hdev->cur_adv_instance = 0x00;
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 Hedbergcab054a2015-11-30 11:21:45 +02003850 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02003851 __hci_req_update_adv_data(&req, 0x00);
3852 __hci_req_update_scan_rsp_data(&req, 0x00);
3853 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003854 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02003855 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003856 }
Johan Hedberg4375f102013-09-25 13:26:10 +03003857
3858 err = hci_req_run(&req, set_advertising_complete);
3859 if (err < 0)
3860 mgmt_pending_remove(cmd);
3861
3862unlock:
3863 hci_dev_unlock(hdev);
3864 return err;
3865}
3866
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003867static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3868 void *data, u16 len)
3869{
3870 struct mgmt_cp_set_static_address *cp = data;
3871 int err;
3872
3873 BT_DBG("%s", hdev->name);
3874
Marcel Holtmann62af4442013-10-02 22:10:32 -07003875 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003876 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3877 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003878
3879 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003880 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3881 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003882
3883 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3884 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02003885 return mgmt_cmd_status(sk, hdev->id,
3886 MGMT_OP_SET_STATIC_ADDRESS,
3887 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003888
3889 /* Two most significant bits shall be set */
3890 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003891 return mgmt_cmd_status(sk, hdev->id,
3892 MGMT_OP_SET_STATIC_ADDRESS,
3893 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003894 }
3895
3896 hci_dev_lock(hdev);
3897
3898 bacpy(&hdev->static_addr, &cp->bdaddr);
3899
Marcel Holtmann93690c22015-03-06 10:11:21 -08003900 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
3901 if (err < 0)
3902 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003903
Marcel Holtmann93690c22015-03-06 10:11:21 -08003904 err = new_settings(hdev, sk);
3905
3906unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003907 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003908 return err;
3909}
3910
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003911static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3912 void *data, u16 len)
3913{
3914 struct mgmt_cp_set_scan_params *cp = data;
3915 __u16 interval, window;
3916 int err;
3917
3918 BT_DBG("%s", hdev->name);
3919
3920 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003921 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3922 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003923
3924 interval = __le16_to_cpu(cp->interval);
3925
3926 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003927 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3928 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003929
3930 window = __le16_to_cpu(cp->window);
3931
3932 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003933 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3934 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003935
Marcel Holtmann899e1072013-10-14 09:55:32 -07003936 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02003937 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3938 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07003939
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003940 hci_dev_lock(hdev);
3941
3942 hdev->le_scan_interval = interval;
3943 hdev->le_scan_window = window;
3944
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003945 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
3946 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003947
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003948 /* If background scan is running, restart it so new parameters are
3949 * loaded.
3950 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003951 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003952 hdev->discovery.state == DISCOVERY_STOPPED) {
3953 struct hci_request req;
3954
3955 hci_req_init(&req, hdev);
3956
3957 hci_req_add_le_scan_disable(&req);
3958 hci_req_add_le_passive_scan(&req);
3959
3960 hci_req_run(&req, NULL);
3961 }
3962
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003963 hci_dev_unlock(hdev);
3964
3965 return err;
3966}
3967
Marcel Holtmann1904a852015-01-11 13:50:44 -08003968static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
3969 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05003970{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003971 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003972
3973 BT_DBG("status 0x%02x", status);
3974
3975 hci_dev_lock(hdev);
3976
Johan Hedberg333ae952015-03-17 13:48:47 +02003977 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003978 if (!cmd)
3979 goto unlock;
3980
3981 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003982 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3983 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05003984 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003985 struct mgmt_mode *cp = cmd->param;
3986
3987 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003988 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003989 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003990 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003991
Johan Hedberg33e38b32013-03-15 17:07:05 -05003992 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3993 new_settings(hdev, cmd->sk);
3994 }
3995
3996 mgmt_pending_remove(cmd);
3997
3998unlock:
3999 hci_dev_unlock(hdev);
4000}
4001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004002static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004003 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004004{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004005 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004006 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004007 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004008 int err;
4009
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004010 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004011
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004012 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004013 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004014 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4015 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004016
Johan Hedberga7e80f22013-01-09 16:05:19 +02004017 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004018 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4019 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004020
Antti Julkuf6422ec2011-06-22 13:11:56 +03004021 hci_dev_lock(hdev);
4022
Johan Hedberg333ae952015-03-17 13:48:47 +02004023 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004024 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4025 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004026 goto unlock;
4027 }
4028
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004029 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004030 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4031 hdev);
4032 goto unlock;
4033 }
4034
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004035 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004036 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004037 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4038 hdev);
4039 new_settings(hdev, sk);
4040 goto unlock;
4041 }
4042
Johan Hedberg33e38b32013-03-15 17:07:05 -05004043 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4044 data, len);
4045 if (!cmd) {
4046 err = -ENOMEM;
4047 goto unlock;
4048 }
4049
4050 hci_req_init(&req, hdev);
4051
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004052 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004053
4054 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004055 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004056 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4057 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004058 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004059 }
4060
Johan Hedberg33e38b32013-03-15 17:07:05 -05004061unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004062 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004063
Antti Julkuf6422ec2011-06-22 13:11:56 +03004064 return err;
4065}
4066
Marcel Holtmann1904a852015-01-11 13:50:44 -08004067static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004068{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004069 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004070
4071 BT_DBG("status 0x%02x", status);
4072
4073 hci_dev_lock(hdev);
4074
Johan Hedberg333ae952015-03-17 13:48:47 +02004075 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004076 if (!cmd)
4077 goto unlock;
4078
4079 if (status) {
4080 u8 mgmt_err = mgmt_status(status);
4081
4082 /* We need to restore the flag if related HCI commands
4083 * failed.
4084 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004085 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004086
Johan Hedberga69e8372015-03-06 21:08:53 +02004087 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004088 } else {
4089 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4090 new_settings(hdev, cmd->sk);
4091 }
4092
4093 mgmt_pending_remove(cmd);
4094
4095unlock:
4096 hci_dev_unlock(hdev);
4097}
4098
4099static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4100{
4101 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004102 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004103 struct hci_request req;
4104 int err;
4105
4106 BT_DBG("request for %s", hdev->name);
4107
4108 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004109 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4110 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004111
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004112 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004113 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4114 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004115
4116 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004117 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4118 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004119
4120 hci_dev_lock(hdev);
4121
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004122 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004123 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4124 goto unlock;
4125 }
4126
4127 if (!hdev_is_powered(hdev)) {
4128 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004129 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4130 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4131 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4132 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4133 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004134 }
4135
Marcel Holtmannce05d602015-03-13 02:11:03 -07004136 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004137
4138 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4139 if (err < 0)
4140 goto unlock;
4141
4142 err = new_settings(hdev, sk);
4143 goto unlock;
4144 }
4145
4146 /* Reject disabling when powered on */
4147 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004148 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4149 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004150 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004151 } else {
4152 /* When configuring a dual-mode controller to operate
4153 * with LE only and using a static address, then switching
4154 * BR/EDR back on is not allowed.
4155 *
4156 * Dual-mode controllers shall operate with the public
4157 * address as its identity address for BR/EDR and LE. So
4158 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004159 *
4160 * The same restrictions applies when secure connections
4161 * has been enabled. For BR/EDR this is a controller feature
4162 * while for LE it is a host stack feature. This means that
4163 * switching BR/EDR back on when secure connections has been
4164 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004165 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004166 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004167 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004168 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004169 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4170 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004171 goto unlock;
4172 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004173 }
4174
Johan Hedberg333ae952015-03-17 13:48:47 +02004175 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004176 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4177 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004178 goto unlock;
4179 }
4180
4181 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4182 if (!cmd) {
4183 err = -ENOMEM;
4184 goto unlock;
4185 }
4186
Johan Hedbergf2252572015-11-18 12:49:20 +02004187 /* We need to flip the bit already here so that
4188 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004189 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004190 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004191
4192 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004193
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004194 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004195 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004196
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004197 /* Since only the advertising data flags will change, there
4198 * is no need to update the scan response data.
4199 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004200 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004201
Johan Hedberg0663ca22013-10-02 13:43:14 +03004202 err = hci_req_run(&req, set_bredr_complete);
4203 if (err < 0)
4204 mgmt_pending_remove(cmd);
4205
4206unlock:
4207 hci_dev_unlock(hdev);
4208 return err;
4209}
4210
Johan Hedberga1443f52015-01-23 15:42:46 +02004211static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4212{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004213 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004214 struct mgmt_mode *cp;
4215
4216 BT_DBG("%s status %u", hdev->name, status);
4217
4218 hci_dev_lock(hdev);
4219
Johan Hedberg333ae952015-03-17 13:48:47 +02004220 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004221 if (!cmd)
4222 goto unlock;
4223
4224 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004225 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4226 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004227 goto remove;
4228 }
4229
4230 cp = cmd->param;
4231
4232 switch (cp->val) {
4233 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004234 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4235 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004236 break;
4237 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004238 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004239 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004240 break;
4241 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004242 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4243 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004244 break;
4245 }
4246
4247 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4248 new_settings(hdev, cmd->sk);
4249
4250remove:
4251 mgmt_pending_remove(cmd);
4252unlock:
4253 hci_dev_unlock(hdev);
4254}
4255
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004256static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4257 void *data, u16 len)
4258{
4259 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004260 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004261 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004262 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004263 int err;
4264
4265 BT_DBG("request for %s", hdev->name);
4266
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004267 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004268 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004269 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4270 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004271
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004272 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004273 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004274 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004275 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4276 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004277
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004278 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004279 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004280 MGMT_STATUS_INVALID_PARAMS);
4281
4282 hci_dev_lock(hdev);
4283
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004284 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004285 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004286 bool changed;
4287
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004288 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004289 changed = !hci_dev_test_and_set_flag(hdev,
4290 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004291 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004292 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004293 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004294 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004295 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004296 changed = hci_dev_test_and_clear_flag(hdev,
4297 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004298 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004299 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004300
4301 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4302 if (err < 0)
4303 goto failed;
4304
4305 if (changed)
4306 err = new_settings(hdev, sk);
4307
4308 goto failed;
4309 }
4310
Johan Hedberg333ae952015-03-17 13:48:47 +02004311 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004312 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4313 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004314 goto failed;
4315 }
4316
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004317 val = !!cp->val;
4318
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004319 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4320 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004321 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4322 goto failed;
4323 }
4324
4325 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4326 if (!cmd) {
4327 err = -ENOMEM;
4328 goto failed;
4329 }
4330
Johan Hedberga1443f52015-01-23 15:42:46 +02004331 hci_req_init(&req, hdev);
4332 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4333 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004334 if (err < 0) {
4335 mgmt_pending_remove(cmd);
4336 goto failed;
4337 }
4338
4339failed:
4340 hci_dev_unlock(hdev);
4341 return err;
4342}
4343
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004344static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4345 void *data, u16 len)
4346{
4347 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004348 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004349 int err;
4350
4351 BT_DBG("request for %s", hdev->name);
4352
Johan Hedbergb97109792014-06-24 14:00:28 +03004353 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004354 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4355 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004356
4357 hci_dev_lock(hdev);
4358
4359 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004360 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004361 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004362 changed = hci_dev_test_and_clear_flag(hdev,
4363 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004364
Johan Hedbergb97109792014-06-24 14:00:28 +03004365 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004366 use_changed = !hci_dev_test_and_set_flag(hdev,
4367 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004368 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004369 use_changed = hci_dev_test_and_clear_flag(hdev,
4370 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004371
4372 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004373 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004374 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4375 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4376 sizeof(mode), &mode);
4377 }
4378
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004379 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4380 if (err < 0)
4381 goto unlock;
4382
4383 if (changed)
4384 err = new_settings(hdev, sk);
4385
4386unlock:
4387 hci_dev_unlock(hdev);
4388 return err;
4389}
4390
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004391static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4392 u16 len)
4393{
4394 struct mgmt_cp_set_privacy *cp = cp_data;
4395 bool changed;
4396 int err;
4397
4398 BT_DBG("request for %s", hdev->name);
4399
4400 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004401 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4402 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004403
4404 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004405 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4406 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004407
4408 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004409 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4410 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004411
4412 hci_dev_lock(hdev);
4413
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004414 /* If user space supports this command it is also expected to
4415 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4416 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004417 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004418
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004419 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004420 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004421 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004422 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004423 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004424 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004425 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004426 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004427 }
4428
4429 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4430 if (err < 0)
4431 goto unlock;
4432
4433 if (changed)
4434 err = new_settings(hdev, sk);
4435
4436unlock:
4437 hci_dev_unlock(hdev);
4438 return err;
4439}
4440
Johan Hedberg41edf162014-02-18 10:19:35 +02004441static bool irk_is_valid(struct mgmt_irk_info *irk)
4442{
4443 switch (irk->addr.type) {
4444 case BDADDR_LE_PUBLIC:
4445 return true;
4446
4447 case BDADDR_LE_RANDOM:
4448 /* Two most significant bits shall be set */
4449 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4450 return false;
4451 return true;
4452 }
4453
4454 return false;
4455}
4456
4457static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4458 u16 len)
4459{
4460 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004461 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4462 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004463 u16 irk_count, expected_len;
4464 int i, err;
4465
4466 BT_DBG("request for %s", hdev->name);
4467
4468 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004469 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4470 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004471
4472 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004473 if (irk_count > max_irk_count) {
4474 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004475 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4476 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004477 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004478
4479 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4480 if (expected_len != len) {
4481 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004482 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004483 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4484 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004485 }
4486
4487 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4488
4489 for (i = 0; i < irk_count; i++) {
4490 struct mgmt_irk_info *key = &cp->irks[i];
4491
4492 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004493 return mgmt_cmd_status(sk, hdev->id,
4494 MGMT_OP_LOAD_IRKS,
4495 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004496 }
4497
4498 hci_dev_lock(hdev);
4499
4500 hci_smp_irks_clear(hdev);
4501
4502 for (i = 0; i < irk_count; i++) {
4503 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004504
Johan Hedberg85813a72015-10-21 18:02:59 +03004505 hci_add_irk(hdev, &irk->addr.bdaddr,
4506 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004507 BDADDR_ANY);
4508 }
4509
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004510 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004511
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004512 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004513
4514 hci_dev_unlock(hdev);
4515
4516 return err;
4517}
4518
Johan Hedberg3f706b72013-01-20 14:27:16 +02004519static bool ltk_is_valid(struct mgmt_ltk_info *key)
4520{
4521 if (key->master != 0x00 && key->master != 0x01)
4522 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004523
4524 switch (key->addr.type) {
4525 case BDADDR_LE_PUBLIC:
4526 return true;
4527
4528 case BDADDR_LE_RANDOM:
4529 /* Two most significant bits shall be set */
4530 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4531 return false;
4532 return true;
4533 }
4534
4535 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004536}
4537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004538static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004539 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004540{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004541 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004542 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4543 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004544 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004545 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004546
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004547 BT_DBG("request for %s", hdev->name);
4548
4549 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004550 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4551 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004552
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004553 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004554 if (key_count > max_key_count) {
4555 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004556 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4557 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004558 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004559
4560 expected_len = sizeof(*cp) + key_count *
4561 sizeof(struct mgmt_ltk_info);
4562 if (expected_len != len) {
4563 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004564 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4566 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004567 }
4568
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004569 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004570
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004571 for (i = 0; i < key_count; i++) {
4572 struct mgmt_ltk_info *key = &cp->keys[i];
4573
Johan Hedberg3f706b72013-01-20 14:27:16 +02004574 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004575 return mgmt_cmd_status(sk, hdev->id,
4576 MGMT_OP_LOAD_LONG_TERM_KEYS,
4577 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004578 }
4579
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004580 hci_dev_lock(hdev);
4581
4582 hci_smp_ltks_clear(hdev);
4583
4584 for (i = 0; i < key_count; i++) {
4585 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004586 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004587
Johan Hedberg61b43352014-05-29 19:36:53 +03004588 switch (key->type) {
4589 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004590 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004591 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004592 break;
4593 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004594 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004595 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004596 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004597 case MGMT_LTK_P256_UNAUTH:
4598 authenticated = 0x00;
4599 type = SMP_LTK_P256;
4600 break;
4601 case MGMT_LTK_P256_AUTH:
4602 authenticated = 0x01;
4603 type = SMP_LTK_P256;
4604 break;
4605 case MGMT_LTK_P256_DEBUG:
4606 authenticated = 0x00;
4607 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004608 default:
4609 continue;
4610 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004611
Johan Hedberg85813a72015-10-21 18:02:59 +03004612 hci_add_ltk(hdev, &key->addr.bdaddr,
4613 le_addr_type(key->addr.type), type, authenticated,
4614 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004615 }
4616
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004617 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004618 NULL, 0);
4619
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004620 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004621
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004622 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004623}
4624
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004625static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004626{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004627 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004628 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004629 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004630
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004631 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004632
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004633 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004634 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004635 rp.tx_power = conn->tx_power;
4636 rp.max_tx_power = conn->max_tx_power;
4637 } else {
4638 rp.rssi = HCI_RSSI_INVALID;
4639 rp.tx_power = HCI_TX_POWER_INVALID;
4640 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004641 }
4642
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004643 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4644 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004645
4646 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004647 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004648
4649 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004650}
4651
Marcel Holtmann1904a852015-01-11 13:50:44 -08004652static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4653 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004654{
4655 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004656 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004657 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004658 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004659 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004660
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004661 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004662
4663 hci_dev_lock(hdev);
4664
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004665 /* Commands sent in request are either Read RSSI or Read Transmit Power
4666 * Level so we check which one was last sent to retrieve connection
4667 * handle. Both commands have handle as first parameter so it's safe to
4668 * cast data on the same command struct.
4669 *
4670 * First command sent is always Read RSSI and we fail only if it fails.
4671 * In other case we simply override error to indicate success as we
4672 * already remembered if TX power value is actually valid.
4673 */
4674 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4675 if (!cp) {
4676 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004677 status = MGMT_STATUS_SUCCESS;
4678 } else {
4679 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004680 }
4681
4682 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004683 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004684 goto unlock;
4685 }
4686
4687 handle = __le16_to_cpu(cp->handle);
4688 conn = hci_conn_hash_lookup_handle(hdev, handle);
4689 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004690 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004691 goto unlock;
4692 }
4693
Johan Hedberg333ae952015-03-17 13:48:47 +02004694 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004695 if (!cmd)
4696 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004697
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004698 cmd->cmd_complete(cmd, status);
4699 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004700
4701unlock:
4702 hci_dev_unlock(hdev);
4703}
4704
4705static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4706 u16 len)
4707{
4708 struct mgmt_cp_get_conn_info *cp = data;
4709 struct mgmt_rp_get_conn_info rp;
4710 struct hci_conn *conn;
4711 unsigned long conn_info_age;
4712 int err = 0;
4713
4714 BT_DBG("%s", hdev->name);
4715
4716 memset(&rp, 0, sizeof(rp));
4717 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4718 rp.addr.type = cp->addr.type;
4719
4720 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004721 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4722 MGMT_STATUS_INVALID_PARAMS,
4723 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004724
4725 hci_dev_lock(hdev);
4726
4727 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004728 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4729 MGMT_STATUS_NOT_POWERED, &rp,
4730 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004731 goto unlock;
4732 }
4733
4734 if (cp->addr.type == BDADDR_BREDR)
4735 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4736 &cp->addr.bdaddr);
4737 else
4738 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4739
4740 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004741 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4742 MGMT_STATUS_NOT_CONNECTED, &rp,
4743 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004744 goto unlock;
4745 }
4746
Johan Hedberg333ae952015-03-17 13:48:47 +02004747 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004748 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4749 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004750 goto unlock;
4751 }
4752
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004753 /* To avoid client trying to guess when to poll again for information we
4754 * calculate conn info age as random value between min/max set in hdev.
4755 */
4756 conn_info_age = hdev->conn_info_min_age +
4757 prandom_u32_max(hdev->conn_info_max_age -
4758 hdev->conn_info_min_age);
4759
4760 /* Query controller to refresh cached values if they are too old or were
4761 * never read.
4762 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004763 if (time_after(jiffies, conn->conn_info_timestamp +
4764 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004765 !conn->conn_info_timestamp) {
4766 struct hci_request req;
4767 struct hci_cp_read_tx_power req_txp_cp;
4768 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004769 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004770
4771 hci_req_init(&req, hdev);
4772 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4773 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4774 &req_rssi_cp);
4775
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004776 /* For LE links TX power does not change thus we don't need to
4777 * query for it once value is known.
4778 */
4779 if (!bdaddr_type_is_le(cp->addr.type) ||
4780 conn->tx_power == HCI_TX_POWER_INVALID) {
4781 req_txp_cp.handle = cpu_to_le16(conn->handle);
4782 req_txp_cp.type = 0x00;
4783 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4784 sizeof(req_txp_cp), &req_txp_cp);
4785 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004786
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004787 /* Max TX power needs to be read only once per connection */
4788 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4789 req_txp_cp.handle = cpu_to_le16(conn->handle);
4790 req_txp_cp.type = 0x01;
4791 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4792 sizeof(req_txp_cp), &req_txp_cp);
4793 }
4794
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004795 err = hci_req_run(&req, conn_info_refresh_complete);
4796 if (err < 0)
4797 goto unlock;
4798
4799 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4800 data, len);
4801 if (!cmd) {
4802 err = -ENOMEM;
4803 goto unlock;
4804 }
4805
4806 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004807 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004808 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004809
4810 conn->conn_info_timestamp = jiffies;
4811 } else {
4812 /* Cache is valid, just reply with values cached in hci_conn */
4813 rp.rssi = conn->rssi;
4814 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004815 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004816
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004817 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4818 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004819 }
4820
4821unlock:
4822 hci_dev_unlock(hdev);
4823 return err;
4824}
4825
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004826static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004827{
4828 struct hci_conn *conn = cmd->user_data;
4829 struct mgmt_rp_get_clock_info rp;
4830 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004831 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004832
4833 memset(&rp, 0, sizeof(rp));
4834 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
4835
4836 if (status)
4837 goto complete;
4838
4839 hdev = hci_dev_get(cmd->index);
4840 if (hdev) {
4841 rp.local_clock = cpu_to_le32(hdev->clock);
4842 hci_dev_put(hdev);
4843 }
4844
4845 if (conn) {
4846 rp.piconet_clock = cpu_to_le32(conn->clock);
4847 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
4848 }
4849
4850complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004851 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
4852 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02004853
4854 if (conn) {
4855 hci_conn_drop(conn);
4856 hci_conn_put(conn);
4857 }
Johan Hedberg9df74652014-12-19 22:26:03 +02004858
4859 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02004860}
4861
Marcel Holtmann1904a852015-01-11 13:50:44 -08004862static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03004863{
Johan Hedberg95868422014-06-28 17:54:07 +03004864 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004865 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004866 struct hci_conn *conn;
4867
4868 BT_DBG("%s status %u", hdev->name, status);
4869
4870 hci_dev_lock(hdev);
4871
4872 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
4873 if (!hci_cp)
4874 goto unlock;
4875
4876 if (hci_cp->which) {
4877 u16 handle = __le16_to_cpu(hci_cp->handle);
4878 conn = hci_conn_hash_lookup_handle(hdev, handle);
4879 } else {
4880 conn = NULL;
4881 }
4882
Johan Hedberg333ae952015-03-17 13:48:47 +02004883 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004884 if (!cmd)
4885 goto unlock;
4886
Johan Hedberg69487372014-12-05 13:36:07 +02004887 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03004888 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03004889
4890unlock:
4891 hci_dev_unlock(hdev);
4892}
4893
4894static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
4895 u16 len)
4896{
4897 struct mgmt_cp_get_clock_info *cp = data;
4898 struct mgmt_rp_get_clock_info rp;
4899 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004900 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004901 struct hci_request req;
4902 struct hci_conn *conn;
4903 int err;
4904
4905 BT_DBG("%s", hdev->name);
4906
4907 memset(&rp, 0, sizeof(rp));
4908 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4909 rp.addr.type = cp->addr.type;
4910
4911 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004912 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4913 MGMT_STATUS_INVALID_PARAMS,
4914 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004915
4916 hci_dev_lock(hdev);
4917
4918 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004919 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4920 MGMT_STATUS_NOT_POWERED, &rp,
4921 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004922 goto unlock;
4923 }
4924
4925 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4926 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4927 &cp->addr.bdaddr);
4928 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004929 err = mgmt_cmd_complete(sk, hdev->id,
4930 MGMT_OP_GET_CLOCK_INFO,
4931 MGMT_STATUS_NOT_CONNECTED,
4932 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004933 goto unlock;
4934 }
4935 } else {
4936 conn = NULL;
4937 }
4938
4939 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
4940 if (!cmd) {
4941 err = -ENOMEM;
4942 goto unlock;
4943 }
4944
Johan Hedberg69487372014-12-05 13:36:07 +02004945 cmd->cmd_complete = clock_info_cmd_complete;
4946
Johan Hedberg95868422014-06-28 17:54:07 +03004947 hci_req_init(&req, hdev);
4948
4949 memset(&hci_cp, 0, sizeof(hci_cp));
4950 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4951
4952 if (conn) {
4953 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004954 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004955
4956 hci_cp.handle = cpu_to_le16(conn->handle);
4957 hci_cp.which = 0x01; /* Piconet clock */
4958 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4959 }
4960
4961 err = hci_req_run(&req, get_clock_info_complete);
4962 if (err < 0)
4963 mgmt_pending_remove(cmd);
4964
4965unlock:
4966 hci_dev_unlock(hdev);
4967 return err;
4968}
4969
Johan Hedberg5a154e62014-12-19 22:26:02 +02004970static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
4971{
4972 struct hci_conn *conn;
4973
4974 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
4975 if (!conn)
4976 return false;
4977
4978 if (conn->dst_type != type)
4979 return false;
4980
4981 if (conn->state != BT_CONNECTED)
4982 return false;
4983
4984 return true;
4985}
4986
4987/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02004988static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02004989 u8 addr_type, u8 auto_connect)
4990{
Johan Hedberg5a154e62014-12-19 22:26:02 +02004991 struct hci_conn_params *params;
4992
4993 params = hci_conn_params_add(hdev, addr, addr_type);
4994 if (!params)
4995 return -EIO;
4996
4997 if (params->auto_connect == auto_connect)
4998 return 0;
4999
5000 list_del_init(&params->action);
5001
5002 switch (auto_connect) {
5003 case HCI_AUTO_CONN_DISABLED:
5004 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005005 /* If auto connect is being disabled when we're trying to
5006 * connect to device, keep connecting.
5007 */
5008 if (params->explicit_connect)
5009 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005010 break;
5011 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005012 if (params->explicit_connect)
5013 list_add(&params->action, &hdev->pend_le_conns);
5014 else
5015 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005016 break;
5017 case HCI_AUTO_CONN_DIRECT:
5018 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005019 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005020 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005021 break;
5022 }
5023
5024 params->auto_connect = auto_connect;
5025
5026 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5027 auto_connect);
5028
5029 return 0;
5030}
5031
Marcel Holtmann8afef092014-06-29 22:28:34 +02005032static void device_added(struct sock *sk, struct hci_dev *hdev,
5033 bdaddr_t *bdaddr, u8 type, u8 action)
5034{
5035 struct mgmt_ev_device_added ev;
5036
5037 bacpy(&ev.addr.bdaddr, bdaddr);
5038 ev.addr.type = type;
5039 ev.action = action;
5040
5041 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5042}
5043
Marcel Holtmann2faade52014-06-29 19:44:03 +02005044static int add_device(struct sock *sk, struct hci_dev *hdev,
5045 void *data, u16 len)
5046{
5047 struct mgmt_cp_add_device *cp = data;
5048 u8 auto_conn, addr_type;
5049 int err;
5050
5051 BT_DBG("%s", hdev->name);
5052
Johan Hedberg66593582014-07-09 12:59:14 +03005053 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005054 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005055 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5056 MGMT_STATUS_INVALID_PARAMS,
5057 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005058
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005059 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005060 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5061 MGMT_STATUS_INVALID_PARAMS,
5062 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005063
5064 hci_dev_lock(hdev);
5065
Johan Hedberg66593582014-07-09 12:59:14 +03005066 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005067 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005068 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005069 err = mgmt_cmd_complete(sk, hdev->id,
5070 MGMT_OP_ADD_DEVICE,
5071 MGMT_STATUS_INVALID_PARAMS,
5072 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005073 goto unlock;
5074 }
5075
5076 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5077 cp->addr.type);
5078 if (err)
5079 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005080
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005081 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005082
Johan Hedberg66593582014-07-09 12:59:14 +03005083 goto added;
5084 }
5085
Johan Hedberg85813a72015-10-21 18:02:59 +03005086 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005087
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005088 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005089 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005090 else if (cp->action == 0x01)
5091 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005092 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005093 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005094
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005095 /* Kernel internally uses conn_params with resolvable private
5096 * address, but Add Device allows only identity addresses.
5097 * Make sure it is enforced before calling
5098 * hci_conn_params_lookup.
5099 */
5100 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005101 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5102 MGMT_STATUS_INVALID_PARAMS,
5103 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005104 goto unlock;
5105 }
5106
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005107 /* If the connection parameters don't exist for this device,
5108 * they will be created and configured with defaults.
5109 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005110 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005111 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005112 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5113 MGMT_STATUS_FAILED, &cp->addr,
5114 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005115 goto unlock;
5116 }
5117
Johan Hedberg51d7a942015-11-11 08:11:18 +02005118 hci_update_background_scan(hdev);
5119
Johan Hedberg66593582014-07-09 12:59:14 +03005120added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005121 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5122
Johan Hedberg51d7a942015-11-11 08:11:18 +02005123 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5124 MGMT_STATUS_SUCCESS, &cp->addr,
5125 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005126
5127unlock:
5128 hci_dev_unlock(hdev);
5129 return err;
5130}
5131
Marcel Holtmann8afef092014-06-29 22:28:34 +02005132static void device_removed(struct sock *sk, struct hci_dev *hdev,
5133 bdaddr_t *bdaddr, u8 type)
5134{
5135 struct mgmt_ev_device_removed ev;
5136
5137 bacpy(&ev.addr.bdaddr, bdaddr);
5138 ev.addr.type = type;
5139
5140 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5141}
5142
Marcel Holtmann2faade52014-06-29 19:44:03 +02005143static int remove_device(struct sock *sk, struct hci_dev *hdev,
5144 void *data, u16 len)
5145{
5146 struct mgmt_cp_remove_device *cp = data;
5147 int err;
5148
5149 BT_DBG("%s", hdev->name);
5150
5151 hci_dev_lock(hdev);
5152
5153 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005154 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005155 u8 addr_type;
5156
Johan Hedberg66593582014-07-09 12:59:14 +03005157 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005158 err = mgmt_cmd_complete(sk, hdev->id,
5159 MGMT_OP_REMOVE_DEVICE,
5160 MGMT_STATUS_INVALID_PARAMS,
5161 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005162 goto unlock;
5163 }
5164
Johan Hedberg66593582014-07-09 12:59:14 +03005165 if (cp->addr.type == BDADDR_BREDR) {
5166 err = hci_bdaddr_list_del(&hdev->whitelist,
5167 &cp->addr.bdaddr,
5168 cp->addr.type);
5169 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005170 err = mgmt_cmd_complete(sk, hdev->id,
5171 MGMT_OP_REMOVE_DEVICE,
5172 MGMT_STATUS_INVALID_PARAMS,
5173 &cp->addr,
5174 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005175 goto unlock;
5176 }
5177
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005178 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005179
Johan Hedberg66593582014-07-09 12:59:14 +03005180 device_removed(sk, hdev, &cp->addr.bdaddr,
5181 cp->addr.type);
5182 goto complete;
5183 }
5184
Johan Hedberg85813a72015-10-21 18:02:59 +03005185 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005186
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005187 /* Kernel internally uses conn_params with resolvable private
5188 * address, but Remove Device allows only identity addresses.
5189 * Make sure it is enforced before calling
5190 * hci_conn_params_lookup.
5191 */
5192 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005193 err = mgmt_cmd_complete(sk, hdev->id,
5194 MGMT_OP_REMOVE_DEVICE,
5195 MGMT_STATUS_INVALID_PARAMS,
5196 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005197 goto unlock;
5198 }
5199
Johan Hedbergc71593d2014-07-02 17:37:28 +03005200 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5201 addr_type);
5202 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005203 err = mgmt_cmd_complete(sk, hdev->id,
5204 MGMT_OP_REMOVE_DEVICE,
5205 MGMT_STATUS_INVALID_PARAMS,
5206 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005207 goto unlock;
5208 }
5209
Johan Hedberg679d2b62015-10-16 10:07:52 +03005210 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5211 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005212 err = mgmt_cmd_complete(sk, hdev->id,
5213 MGMT_OP_REMOVE_DEVICE,
5214 MGMT_STATUS_INVALID_PARAMS,
5215 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005216 goto unlock;
5217 }
5218
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005219 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005220 list_del(&params->list);
5221 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005222 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005223
5224 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005225 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005226 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005227 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005228
Marcel Holtmann2faade52014-06-29 19:44:03 +02005229 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005230 err = mgmt_cmd_complete(sk, hdev->id,
5231 MGMT_OP_REMOVE_DEVICE,
5232 MGMT_STATUS_INVALID_PARAMS,
5233 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005234 goto unlock;
5235 }
5236
Johan Hedberg66593582014-07-09 12:59:14 +03005237 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5238 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5239 list_del(&b->list);
5240 kfree(b);
5241 }
5242
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005243 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005244
Johan Hedberg19de0822014-07-06 13:06:51 +03005245 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5246 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5247 continue;
5248 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005249 if (p->explicit_connect) {
5250 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5251 continue;
5252 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005253 list_del(&p->action);
5254 list_del(&p->list);
5255 kfree(p);
5256 }
5257
5258 BT_DBG("All LE connection parameters were removed");
5259
Johan Hedberg51d7a942015-11-11 08:11:18 +02005260 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005261 }
5262
Johan Hedberg66593582014-07-09 12:59:14 +03005263complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005264 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5265 MGMT_STATUS_SUCCESS, &cp->addr,
5266 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005267unlock:
5268 hci_dev_unlock(hdev);
5269 return err;
5270}
5271
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005272static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5273 u16 len)
5274{
5275 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005276 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5277 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005278 u16 param_count, expected_len;
5279 int i;
5280
5281 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005282 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5283 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005284
5285 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005286 if (param_count > max_param_count) {
5287 BT_ERR("load_conn_param: too big param_count value %u",
5288 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005289 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5290 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005291 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005292
5293 expected_len = sizeof(*cp) + param_count *
5294 sizeof(struct mgmt_conn_param);
5295 if (expected_len != len) {
5296 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5297 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005298 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5299 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005300 }
5301
5302 BT_DBG("%s param_count %u", hdev->name, param_count);
5303
5304 hci_dev_lock(hdev);
5305
5306 hci_conn_params_clear_disabled(hdev);
5307
5308 for (i = 0; i < param_count; i++) {
5309 struct mgmt_conn_param *param = &cp->params[i];
5310 struct hci_conn_params *hci_param;
5311 u16 min, max, latency, timeout;
5312 u8 addr_type;
5313
5314 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5315 param->addr.type);
5316
5317 if (param->addr.type == BDADDR_LE_PUBLIC) {
5318 addr_type = ADDR_LE_DEV_PUBLIC;
5319 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5320 addr_type = ADDR_LE_DEV_RANDOM;
5321 } else {
5322 BT_ERR("Ignoring invalid connection parameters");
5323 continue;
5324 }
5325
5326 min = le16_to_cpu(param->min_interval);
5327 max = le16_to_cpu(param->max_interval);
5328 latency = le16_to_cpu(param->latency);
5329 timeout = le16_to_cpu(param->timeout);
5330
5331 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5332 min, max, latency, timeout);
5333
5334 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5335 BT_ERR("Ignoring invalid connection parameters");
5336 continue;
5337 }
5338
5339 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5340 addr_type);
5341 if (!hci_param) {
5342 BT_ERR("Failed to add connection parameters");
5343 continue;
5344 }
5345
5346 hci_param->conn_min_interval = min;
5347 hci_param->conn_max_interval = max;
5348 hci_param->conn_latency = latency;
5349 hci_param->supervision_timeout = timeout;
5350 }
5351
5352 hci_dev_unlock(hdev);
5353
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005354 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5355 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005356}
5357
Marcel Holtmanndbece372014-07-04 18:11:55 +02005358static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5359 void *data, u16 len)
5360{
5361 struct mgmt_cp_set_external_config *cp = data;
5362 bool changed;
5363 int err;
5364
5365 BT_DBG("%s", hdev->name);
5366
5367 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005368 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5369 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005370
5371 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005372 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5373 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005374
5375 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005376 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5377 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005378
5379 hci_dev_lock(hdev);
5380
5381 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005382 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005383 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005384 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005385
5386 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5387 if (err < 0)
5388 goto unlock;
5389
5390 if (!changed)
5391 goto unlock;
5392
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005393 err = new_options(hdev, sk);
5394
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005395 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005396 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005397
Marcel Holtmann516018a2015-03-13 02:11:04 -07005398 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005399 hci_dev_set_flag(hdev, HCI_CONFIG);
5400 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005401
5402 queue_work(hdev->req_workqueue, &hdev->power_on);
5403 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005404 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005405 mgmt_index_added(hdev);
5406 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005407 }
5408
5409unlock:
5410 hci_dev_unlock(hdev);
5411 return err;
5412}
5413
Marcel Holtmann9713c172014-07-06 12:11:15 +02005414static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5415 void *data, u16 len)
5416{
5417 struct mgmt_cp_set_public_address *cp = data;
5418 bool changed;
5419 int err;
5420
5421 BT_DBG("%s", hdev->name);
5422
5423 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005424 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5425 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005426
5427 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005428 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5429 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005430
5431 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005432 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5433 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005434
5435 hci_dev_lock(hdev);
5436
5437 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5438 bacpy(&hdev->public_addr, &cp->bdaddr);
5439
5440 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5441 if (err < 0)
5442 goto unlock;
5443
5444 if (!changed)
5445 goto unlock;
5446
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005447 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005448 err = new_options(hdev, sk);
5449
5450 if (is_configured(hdev)) {
5451 mgmt_index_removed(hdev);
5452
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005453 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005454
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005455 hci_dev_set_flag(hdev, HCI_CONFIG);
5456 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005457
5458 queue_work(hdev->req_workqueue, &hdev->power_on);
5459 }
5460
5461unlock:
5462 hci_dev_unlock(hdev);
5463 return err;
5464}
5465
Marcel Holtmannbea41602015-03-14 22:43:17 -07005466static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5467 u8 data_len)
5468{
5469 eir[eir_len++] = sizeof(type) + data_len;
5470 eir[eir_len++] = type;
5471 memcpy(&eir[eir_len], data, data_len);
5472 eir_len += data_len;
5473
5474 return eir_len;
5475}
5476
Johan Hedberg40f66c02015-04-07 21:52:22 +03005477static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5478 u16 opcode, struct sk_buff *skb)
5479{
5480 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5481 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5482 u8 *h192, *r192, *h256, *r256;
5483 struct mgmt_pending_cmd *cmd;
5484 u16 eir_len;
5485 int err;
5486
5487 BT_DBG("%s status %u", hdev->name, status);
5488
5489 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5490 if (!cmd)
5491 return;
5492
5493 mgmt_cp = cmd->param;
5494
5495 if (status) {
5496 status = mgmt_status(status);
5497 eir_len = 0;
5498
5499 h192 = NULL;
5500 r192 = NULL;
5501 h256 = NULL;
5502 r256 = NULL;
5503 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5504 struct hci_rp_read_local_oob_data *rp;
5505
5506 if (skb->len != sizeof(*rp)) {
5507 status = MGMT_STATUS_FAILED;
5508 eir_len = 0;
5509 } else {
5510 status = MGMT_STATUS_SUCCESS;
5511 rp = (void *)skb->data;
5512
5513 eir_len = 5 + 18 + 18;
5514 h192 = rp->hash;
5515 r192 = rp->rand;
5516 h256 = NULL;
5517 r256 = NULL;
5518 }
5519 } else {
5520 struct hci_rp_read_local_oob_ext_data *rp;
5521
5522 if (skb->len != sizeof(*rp)) {
5523 status = MGMT_STATUS_FAILED;
5524 eir_len = 0;
5525 } else {
5526 status = MGMT_STATUS_SUCCESS;
5527 rp = (void *)skb->data;
5528
5529 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5530 eir_len = 5 + 18 + 18;
5531 h192 = NULL;
5532 r192 = NULL;
5533 } else {
5534 eir_len = 5 + 18 + 18 + 18 + 18;
5535 h192 = rp->hash192;
5536 r192 = rp->rand192;
5537 }
5538
5539 h256 = rp->hash256;
5540 r256 = rp->rand256;
5541 }
5542 }
5543
5544 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5545 if (!mgmt_rp)
5546 goto done;
5547
5548 if (status)
5549 goto send_rsp;
5550
5551 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5552 hdev->dev_class, 3);
5553
5554 if (h192 && r192) {
5555 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5556 EIR_SSP_HASH_C192, h192, 16);
5557 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5558 EIR_SSP_RAND_R192, r192, 16);
5559 }
5560
5561 if (h256 && r256) {
5562 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5563 EIR_SSP_HASH_C256, h256, 16);
5564 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5565 EIR_SSP_RAND_R256, r256, 16);
5566 }
5567
5568send_rsp:
5569 mgmt_rp->type = mgmt_cp->type;
5570 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5571
5572 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5573 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5574 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5575 if (err < 0 || status)
5576 goto done;
5577
5578 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5579
5580 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5581 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5582 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5583done:
5584 kfree(mgmt_rp);
5585 mgmt_pending_remove(cmd);
5586}
5587
5588static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5589 struct mgmt_cp_read_local_oob_ext_data *cp)
5590{
5591 struct mgmt_pending_cmd *cmd;
5592 struct hci_request req;
5593 int err;
5594
5595 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5596 cp, sizeof(*cp));
5597 if (!cmd)
5598 return -ENOMEM;
5599
5600 hci_req_init(&req, hdev);
5601
5602 if (bredr_sc_enabled(hdev))
5603 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5604 else
5605 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5606
5607 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5608 if (err < 0) {
5609 mgmt_pending_remove(cmd);
5610 return err;
5611 }
5612
5613 return 0;
5614}
5615
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005616static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5617 void *data, u16 data_len)
5618{
5619 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5620 struct mgmt_rp_read_local_oob_ext_data *rp;
5621 size_t rp_len;
5622 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005623 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005624 int err;
5625
5626 BT_DBG("%s", hdev->name);
5627
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005628 if (hdev_is_powered(hdev)) {
5629 switch (cp->type) {
5630 case BIT(BDADDR_BREDR):
5631 status = mgmt_bredr_support(hdev);
5632 if (status)
5633 eir_len = 0;
5634 else
5635 eir_len = 5;
5636 break;
5637 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5638 status = mgmt_le_support(hdev);
5639 if (status)
5640 eir_len = 0;
5641 else
5642 eir_len = 9 + 3 + 18 + 18 + 3;
5643 break;
5644 default:
5645 status = MGMT_STATUS_INVALID_PARAMS;
5646 eir_len = 0;
5647 break;
5648 }
5649 } else {
5650 status = MGMT_STATUS_NOT_POWERED;
5651 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005652 }
5653
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005654 rp_len = sizeof(*rp) + eir_len;
5655 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005656 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005657 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005658
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005659 if (status)
5660 goto complete;
5661
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005662 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005663
5664 eir_len = 0;
5665 switch (cp->type) {
5666 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005667 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5668 err = read_local_ssp_oob_req(hdev, sk, cp);
5669 hci_dev_unlock(hdev);
5670 if (!err)
5671 goto done;
5672
5673 status = MGMT_STATUS_FAILED;
5674 goto complete;
5675 } else {
5676 eir_len = eir_append_data(rp->eir, eir_len,
5677 EIR_CLASS_OF_DEV,
5678 hdev->dev_class, 3);
5679 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005680 break;
5681 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005682 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5683 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005684 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005685 status = MGMT_STATUS_FAILED;
5686 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005687 }
5688
Marcel Holtmanne2135682015-04-02 12:00:58 -07005689 /* This should return the active RPA, but since the RPA
5690 * is only programmed on demand, it is really hard to fill
5691 * this in at the moment. For now disallow retrieving
5692 * local out-of-band data when privacy is in use.
5693 *
5694 * Returning the identity address will not help here since
5695 * pairing happens before the identity resolving key is
5696 * known and thus the connection establishment happens
5697 * based on the RPA and not the identity address.
5698 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005699 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005700 hci_dev_unlock(hdev);
5701 status = MGMT_STATUS_REJECTED;
5702 goto complete;
5703 }
5704
5705 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5706 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5707 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5708 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005709 memcpy(addr, &hdev->static_addr, 6);
5710 addr[6] = 0x01;
5711 } else {
5712 memcpy(addr, &hdev->bdaddr, 6);
5713 addr[6] = 0x00;
5714 }
5715
5716 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5717 addr, sizeof(addr));
5718
5719 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5720 role = 0x02;
5721 else
5722 role = 0x01;
5723
5724 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5725 &role, sizeof(role));
5726
Marcel Holtmann5082a592015-03-16 12:39:00 -07005727 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5728 eir_len = eir_append_data(rp->eir, eir_len,
5729 EIR_LE_SC_CONFIRM,
5730 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005731
Marcel Holtmann5082a592015-03-16 12:39:00 -07005732 eir_len = eir_append_data(rp->eir, eir_len,
5733 EIR_LE_SC_RANDOM,
5734 rand, sizeof(rand));
5735 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005736
Johan Hedbergf2252572015-11-18 12:49:20 +02005737 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005738
5739 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5740 flags |= LE_AD_NO_BREDR;
5741
5742 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5743 &flags, sizeof(flags));
5744 break;
5745 }
5746
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005747 hci_dev_unlock(hdev);
5748
Marcel Holtmann72000df2015-03-16 16:11:21 -07005749 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5750
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005751 status = MGMT_STATUS_SUCCESS;
5752
5753complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005754 rp->type = cp->type;
5755 rp->eir_len = cpu_to_le16(eir_len);
5756
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005757 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005758 status, rp, sizeof(*rp) + eir_len);
5759 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005760 goto done;
5761
5762 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5763 rp, sizeof(*rp) + eir_len,
5764 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005765
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005766done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005767 kfree(rp);
5768
5769 return err;
5770}
5771
Arman Uguray089fa8c2015-03-25 18:53:45 -07005772static u32 get_supported_adv_flags(struct hci_dev *hdev)
5773{
5774 u32 flags = 0;
5775
5776 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5777 flags |= MGMT_ADV_FLAG_DISCOV;
5778 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5779 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
5780
5781 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5782 flags |= MGMT_ADV_FLAG_TX_POWER;
5783
5784 return flags;
5785}
5786
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005787static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5788 void *data, u16 data_len)
5789{
5790 struct mgmt_rp_read_adv_features *rp;
5791 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005792 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005793 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005794 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005795 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005796
5797 BT_DBG("%s", hdev->name);
5798
Arman Uguray089fa8c2015-03-25 18:53:45 -07005799 if (!lmp_le_capable(hdev))
5800 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5801 MGMT_STATUS_REJECTED);
5802
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005803 hci_dev_lock(hdev);
5804
Johan Hedberg02c04af2015-11-26 12:15:58 +02005805 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005806 rp = kmalloc(rp_len, GFP_ATOMIC);
5807 if (!rp) {
5808 hci_dev_unlock(hdev);
5809 return -ENOMEM;
5810 }
5811
Arman Uguray089fa8c2015-03-25 18:53:45 -07005812 supported_flags = get_supported_adv_flags(hdev);
5813
5814 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005815 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5816 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005817 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005818 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005819
Johan Hedberg02c04af2015-11-26 12:15:58 +02005820 instance = rp->instance;
5821 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5822 *instance = adv_instance->instance;
5823 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005824 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005825
5826 hci_dev_unlock(hdev);
5827
5828 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5829 MGMT_STATUS_SUCCESS, rp, rp_len);
5830
5831 kfree(rp);
5832
5833 return err;
5834}
5835
Arman Uguray4117ed72015-03-23 15:57:14 -07005836static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005837 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005838{
Arman Uguray4117ed72015-03-23 15:57:14 -07005839 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005840 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005841 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005842 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005843
Marcel Holtmann31a32482015-11-19 16:16:42 +01005844 if (is_adv_data) {
5845 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5846 MGMT_ADV_FLAG_LIMITED_DISCOV |
5847 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5848 flags_managed = true;
5849 max_len -= 3;
5850 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005851
Marcel Holtmann31a32482015-11-19 16:16:42 +01005852 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5853 tx_power_managed = true;
5854 max_len -= 3;
5855 }
Arman Uguray5507e352015-03-25 18:53:44 -07005856 }
5857
Arman Uguray4117ed72015-03-23 15:57:14 -07005858 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005859 return false;
5860
Arman Uguray4117ed72015-03-23 15:57:14 -07005861 /* Make sure that the data is correctly formatted. */
5862 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
5863 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07005864
Arman Ugurayb44133f2015-03-25 18:53:41 -07005865 if (flags_managed && data[i + 1] == EIR_FLAGS)
5866 return false;
5867
Arman Uguray5507e352015-03-25 18:53:44 -07005868 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
5869 return false;
5870
Arman Uguray24b4f382015-03-23 15:57:12 -07005871 /* If the current field length would exceed the total data
5872 * length, then it's invalid.
5873 */
Arman Uguray4117ed72015-03-23 15:57:14 -07005874 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005875 return false;
5876 }
5877
5878 return true;
5879}
5880
Arman Uguray24b4f382015-03-23 15:57:12 -07005881static void add_advertising_complete(struct hci_dev *hdev, u8 status,
5882 u16 opcode)
5883{
5884 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005885 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07005886 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005887 struct adv_info *adv_instance, *n;
5888 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005889
5890 BT_DBG("status %d", status);
5891
5892 hci_dev_lock(hdev);
5893
5894 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
5895
Florian Grandelfffd38b2015-06-18 03:16:47 +02005896 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
5897 if (!adv_instance->pending)
5898 continue;
5899
5900 if (!status) {
5901 adv_instance->pending = false;
5902 continue;
5903 }
5904
5905 instance = adv_instance->instance;
5906
5907 if (hdev->cur_adv_instance == instance)
5908 cancel_adv_timeout(hdev);
5909
5910 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02005911 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07005912 }
5913
5914 if (!cmd)
5915 goto unlock;
5916
Florian Grandelfffd38b2015-06-18 03:16:47 +02005917 cp = cmd->param;
5918 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005919
5920 if (status)
5921 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5922 mgmt_status(status));
5923 else
5924 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
5925 mgmt_status(status), &rp, sizeof(rp));
5926
5927 mgmt_pending_remove(cmd);
5928
5929unlock:
5930 hci_dev_unlock(hdev);
5931}
5932
5933static int add_advertising(struct sock *sk, struct hci_dev *hdev,
5934 void *data, u16 data_len)
5935{
5936 struct mgmt_cp_add_advertising *cp = data;
5937 struct mgmt_rp_add_advertising rp;
5938 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005939 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07005940 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005941 u16 timeout, duration;
5942 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
5943 u8 schedule_instance = 0;
5944 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005945 int err;
5946 struct mgmt_pending_cmd *cmd;
5947 struct hci_request req;
5948
5949 BT_DBG("%s", hdev->name);
5950
5951 status = mgmt_le_support(hdev);
5952 if (status)
5953 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5954 status);
5955
Marcel Holtmannceff86a2015-11-19 16:16:41 +01005956 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
5957 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5958 MGMT_STATUS_INVALID_PARAMS);
5959
Arman Uguray24b4f382015-03-23 15:57:12 -07005960 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07005961 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005962 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07005963
Florian Grandelfffd38b2015-06-18 03:16:47 +02005964 /* The current implementation only supports a subset of the specified
5965 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07005966 */
5967 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005968 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07005969 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5970 MGMT_STATUS_INVALID_PARAMS);
5971
5972 hci_dev_lock(hdev);
5973
Arman Uguray912098a2015-03-23 15:57:15 -07005974 if (timeout && !hdev_is_powered(hdev)) {
5975 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5976 MGMT_STATUS_REJECTED);
5977 goto unlock;
5978 }
5979
Arman Uguray24b4f382015-03-23 15:57:12 -07005980 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07005981 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07005982 pending_find(MGMT_OP_SET_LE, hdev)) {
5983 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5984 MGMT_STATUS_BUSY);
5985 goto unlock;
5986 }
5987
Arman Ugurayb44133f2015-03-25 18:53:41 -07005988 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07005989 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005990 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07005991 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5992 MGMT_STATUS_INVALID_PARAMS);
5993 goto unlock;
5994 }
5995
Florian Grandelfffd38b2015-06-18 03:16:47 +02005996 err = hci_add_adv_instance(hdev, cp->instance, flags,
5997 cp->adv_data_len, cp->data,
5998 cp->scan_rsp_len,
5999 cp->data + cp->adv_data_len,
6000 timeout, duration);
6001 if (err < 0) {
6002 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6003 MGMT_STATUS_FAILED);
6004 goto unlock;
6005 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006006
Florian Grandelfffd38b2015-06-18 03:16:47 +02006007 /* Only trigger an advertising added event if a new instance was
6008 * actually added.
6009 */
6010 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006011 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006012
Florian Grandelfffd38b2015-06-18 03:16:47 +02006013 if (hdev->cur_adv_instance == cp->instance) {
6014 /* If the currently advertised instance is being changed then
6015 * cancel the current advertising and schedule the next
6016 * instance. If there is only one instance then the overridden
6017 * advertising data will be visible right away.
6018 */
6019 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006020
Florian Grandelfffd38b2015-06-18 03:16:47 +02006021 next_instance = hci_get_next_instance(hdev, cp->instance);
6022 if (next_instance)
6023 schedule_instance = next_instance->instance;
6024 } else if (!hdev->adv_instance_timeout) {
6025 /* Immediately advertise the new instance if no other
6026 * instance is currently being advertised.
6027 */
6028 schedule_instance = cp->instance;
6029 }
Arman Uguray912098a2015-03-23 15:57:15 -07006030
Florian Grandelfffd38b2015-06-18 03:16:47 +02006031 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6032 * there is no instance to be advertised then we have no HCI
6033 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006034 */
6035 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006036 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6037 !schedule_instance) {
6038 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006039 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6040 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6041 goto unlock;
6042 }
6043
6044 /* We're good to go, update advertising data, parameters, and start
6045 * advertising.
6046 */
6047 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6048 data_len);
6049 if (!cmd) {
6050 err = -ENOMEM;
6051 goto unlock;
6052 }
6053
6054 hci_req_init(&req, hdev);
6055
Johan Hedbergf2252572015-11-18 12:49:20 +02006056 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006057
Florian Grandelfffd38b2015-06-18 03:16:47 +02006058 if (!err)
6059 err = hci_req_run(&req, add_advertising_complete);
6060
Arman Uguray24b4f382015-03-23 15:57:12 -07006061 if (err < 0)
6062 mgmt_pending_remove(cmd);
6063
6064unlock:
6065 hci_dev_unlock(hdev);
6066
6067 return err;
6068}
6069
Arman Ugurayda9293352015-03-23 15:57:13 -07006070static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6071 u16 opcode)
6072{
6073 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006074 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006075 struct mgmt_rp_remove_advertising rp;
6076
6077 BT_DBG("status %d", status);
6078
6079 hci_dev_lock(hdev);
6080
6081 /* A failure status here only means that we failed to disable
6082 * advertising. Otherwise, the advertising instance has been removed,
6083 * so report success.
6084 */
6085 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6086 if (!cmd)
6087 goto unlock;
6088
Florian Grandel01948332015-06-18 03:16:48 +02006089 cp = cmd->param;
6090 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006091
6092 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6093 &rp, sizeof(rp));
6094 mgmt_pending_remove(cmd);
6095
6096unlock:
6097 hci_dev_unlock(hdev);
6098}
6099
6100static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6101 void *data, u16 data_len)
6102{
6103 struct mgmt_cp_remove_advertising *cp = data;
6104 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006105 struct mgmt_pending_cmd *cmd;
6106 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006107 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006108
6109 BT_DBG("%s", hdev->name);
6110
Arman Ugurayda9293352015-03-23 15:57:13 -07006111 hci_dev_lock(hdev);
6112
Johan Hedberg952497b2015-06-18 21:05:31 +03006113 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006114 err = mgmt_cmd_status(sk, hdev->id,
6115 MGMT_OP_REMOVE_ADVERTISING,
6116 MGMT_STATUS_INVALID_PARAMS);
6117 goto unlock;
6118 }
6119
Arman Ugurayda9293352015-03-23 15:57:13 -07006120 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6121 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6122 pending_find(MGMT_OP_SET_LE, hdev)) {
6123 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6124 MGMT_STATUS_BUSY);
6125 goto unlock;
6126 }
6127
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006128 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006129 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6130 MGMT_STATUS_INVALID_PARAMS);
6131 goto unlock;
6132 }
6133
Florian Grandel01948332015-06-18 03:16:48 +02006134 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006135
Johan Hedbergf2252572015-11-18 12:49:20 +02006136 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006137
Florian Grandel01948332015-06-18 03:16:48 +02006138 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006139 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006140
Florian Grandel01948332015-06-18 03:16:48 +02006141 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6142 * flag is set or the device isn't powered then we have no HCI
6143 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006144 */
Florian Grandel01948332015-06-18 03:16:48 +02006145 if (skb_queue_empty(&req.cmd_q) ||
6146 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006147 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006148 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006149 err = mgmt_cmd_complete(sk, hdev->id,
6150 MGMT_OP_REMOVE_ADVERTISING,
6151 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6152 goto unlock;
6153 }
6154
6155 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6156 data_len);
6157 if (!cmd) {
6158 err = -ENOMEM;
6159 goto unlock;
6160 }
6161
Arman Ugurayda9293352015-03-23 15:57:13 -07006162 err = hci_req_run(&req, remove_advertising_complete);
6163 if (err < 0)
6164 mgmt_pending_remove(cmd);
6165
6166unlock:
6167 hci_dev_unlock(hdev);
6168
6169 return err;
6170}
6171
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006172static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6173{
6174 u8 max_len = HCI_MAX_AD_LENGTH;
6175
6176 if (is_adv_data) {
6177 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6178 MGMT_ADV_FLAG_LIMITED_DISCOV |
6179 MGMT_ADV_FLAG_MANAGED_FLAGS))
6180 max_len -= 3;
6181
6182 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6183 max_len -= 3;
6184 }
6185
6186 return max_len;
6187}
6188
6189static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6190 void *data, u16 data_len)
6191{
6192 struct mgmt_cp_get_adv_size_info *cp = data;
6193 struct mgmt_rp_get_adv_size_info rp;
6194 u32 flags, supported_flags;
6195 int err;
6196
6197 BT_DBG("%s", hdev->name);
6198
6199 if (!lmp_le_capable(hdev))
6200 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6201 MGMT_STATUS_REJECTED);
6202
6203 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6204 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6205 MGMT_STATUS_INVALID_PARAMS);
6206
6207 flags = __le32_to_cpu(cp->flags);
6208
6209 /* The current implementation only supports a subset of the specified
6210 * flags.
6211 */
6212 supported_flags = get_supported_adv_flags(hdev);
6213 if (flags & ~supported_flags)
6214 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6215 MGMT_STATUS_INVALID_PARAMS);
6216
6217 rp.instance = cp->instance;
6218 rp.flags = cp->flags;
6219 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6220 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6221
6222 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6223 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6224
6225 return err;
6226}
6227
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006228static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006229 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006230 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006231 HCI_MGMT_NO_HDEV |
6232 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006233 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006234 HCI_MGMT_NO_HDEV |
6235 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006236 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006237 HCI_MGMT_NO_HDEV |
6238 HCI_MGMT_UNTRUSTED },
6239 { read_controller_info, MGMT_READ_INFO_SIZE,
6240 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006241 { set_powered, MGMT_SETTING_SIZE },
6242 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6243 { set_connectable, MGMT_SETTING_SIZE },
6244 { set_fast_connectable, MGMT_SETTING_SIZE },
6245 { set_bondable, MGMT_SETTING_SIZE },
6246 { set_link_security, MGMT_SETTING_SIZE },
6247 { set_ssp, MGMT_SETTING_SIZE },
6248 { set_hs, MGMT_SETTING_SIZE },
6249 { set_le, MGMT_SETTING_SIZE },
6250 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6251 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6252 { add_uuid, MGMT_ADD_UUID_SIZE },
6253 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006254 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6255 HCI_MGMT_VAR_LEN },
6256 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6257 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006258 { disconnect, MGMT_DISCONNECT_SIZE },
6259 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6260 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6261 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6262 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6263 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6264 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6265 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6266 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6267 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6268 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6269 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006270 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6271 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6272 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006273 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6274 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6275 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6276 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6277 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6278 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6279 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6280 { set_advertising, MGMT_SETTING_SIZE },
6281 { set_bredr, MGMT_SETTING_SIZE },
6282 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6283 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6284 { set_secure_conn, MGMT_SETTING_SIZE },
6285 { set_debug_keys, MGMT_SETTING_SIZE },
6286 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006287 { load_irks, MGMT_LOAD_IRKS_SIZE,
6288 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006289 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6290 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6291 { add_device, MGMT_ADD_DEVICE_SIZE },
6292 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006293 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6294 HCI_MGMT_VAR_LEN },
6295 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006296 HCI_MGMT_NO_HDEV |
6297 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006298 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006299 HCI_MGMT_UNCONFIGURED |
6300 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006301 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6302 HCI_MGMT_UNCONFIGURED },
6303 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6304 HCI_MGMT_UNCONFIGURED },
6305 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6306 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006307 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006308 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006309 HCI_MGMT_NO_HDEV |
6310 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006311 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006312 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6313 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006314 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006315 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006316};
6317
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006318void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006319{
Marcel Holtmannced85542015-03-14 19:27:56 -07006320 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006321
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006322 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6323 return;
6324
Marcel Holtmannf9207332015-03-14 19:27:55 -07006325 switch (hdev->dev_type) {
6326 case HCI_BREDR:
6327 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6328 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6329 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006330 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006331 } else {
6332 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6333 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006334 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006335 }
6336 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006337 case HCI_AMP:
6338 ev.type = 0x02;
6339 break;
6340 default:
6341 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006342 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006343
6344 ev.bus = hdev->bus;
6345
6346 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6347 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006348}
6349
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006350void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006351{
Marcel Holtmannced85542015-03-14 19:27:56 -07006352 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006353 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006354
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006355 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6356 return;
6357
Marcel Holtmannf9207332015-03-14 19:27:55 -07006358 switch (hdev->dev_type) {
6359 case HCI_BREDR:
6360 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006361
Marcel Holtmannf9207332015-03-14 19:27:55 -07006362 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6363 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6364 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006365 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006366 } else {
6367 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6368 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006369 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006370 }
6371 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006372 case HCI_AMP:
6373 ev.type = 0x02;
6374 break;
6375 default:
6376 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006377 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006378
6379 ev.bus = hdev->bus;
6380
6381 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6382 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006383}
6384
Andre Guedes6046dc32014-02-26 20:21:51 -03006385/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006386static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006387{
6388 struct hci_conn_params *p;
6389
6390 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006391 /* Needed for AUTO_OFF case where might not "really"
6392 * have been powered off.
6393 */
6394 list_del_init(&p->action);
6395
6396 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006397 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006398 case HCI_AUTO_CONN_ALWAYS:
6399 list_add(&p->action, &hdev->pend_le_conns);
6400 break;
6401 case HCI_AUTO_CONN_REPORT:
6402 list_add(&p->action, &hdev->pend_le_reports);
6403 break;
6404 default:
6405 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006406 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006407 }
6408}
6409
Johan Hedberg2ff13892015-11-25 16:15:44 +02006410void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006411{
6412 struct cmd_lookup match = { NULL, hdev };
6413
Johan Hedberg2ff13892015-11-25 16:15:44 +02006414 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006415
Johan Hedberg2ff13892015-11-25 16:15:44 +02006416 hci_dev_lock(hdev);
6417
6418 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006419 restart_le_actions(hdev);
6420 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006421 }
6422
Johan Hedberg229ab392013-03-15 17:06:53 -05006423 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6424
6425 new_settings(hdev, match.sk);
6426
Johan Hedberg229ab392013-03-15 17:06:53 -05006427 if (match.sk)
6428 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006429
6430 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006431}
6432
Johan Hedberg2ff13892015-11-25 16:15:44 +02006433void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006434{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006435 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006436 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006437
Johan Hedberg229ab392013-03-15 17:06:53 -05006438 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006439
6440 /* If the power off is because of hdev unregistration let
6441 * use the appropriate INVALID_INDEX status. Otherwise use
6442 * NOT_POWERED. We cover both scenarios here since later in
6443 * mgmt_index_removed() any hci_conn callbacks will have already
6444 * been triggered, potentially causing misleading DISCONNECTED
6445 * status responses.
6446 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006447 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006448 status = MGMT_STATUS_INVALID_INDEX;
6449 else
6450 status = MGMT_STATUS_NOT_POWERED;
6451
6452 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006453
6454 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006455 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6456 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006457
Johan Hedberg2ff13892015-11-25 16:15:44 +02006458 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006459
6460 if (match.sk)
6461 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006462}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006463
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006464void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006465{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006466 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006467 u8 status;
6468
Johan Hedberg333ae952015-03-17 13:48:47 +02006469 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006470 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006471 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006472
6473 if (err == -ERFKILL)
6474 status = MGMT_STATUS_RFKILLED;
6475 else
6476 status = MGMT_STATUS_FAILED;
6477
Johan Hedberga69e8372015-03-06 21:08:53 +02006478 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006479
6480 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006481}
6482
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006483void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6484 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006485{
Johan Hedberg86742e12011-11-07 23:13:38 +02006486 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006487
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006488 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006489
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006490 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006491 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006492 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006493 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006494 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006495 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006496
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006497 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006498}
Johan Hedbergf7520542011-01-20 12:34:39 +02006499
Johan Hedbergd7b25452014-05-23 13:19:53 +03006500static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6501{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006502 switch (ltk->type) {
6503 case SMP_LTK:
6504 case SMP_LTK_SLAVE:
6505 if (ltk->authenticated)
6506 return MGMT_LTK_AUTHENTICATED;
6507 return MGMT_LTK_UNAUTHENTICATED;
6508 case SMP_LTK_P256:
6509 if (ltk->authenticated)
6510 return MGMT_LTK_P256_AUTH;
6511 return MGMT_LTK_P256_UNAUTH;
6512 case SMP_LTK_P256_DEBUG:
6513 return MGMT_LTK_P256_DEBUG;
6514 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006515
6516 return MGMT_LTK_UNAUTHENTICATED;
6517}
6518
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006519void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006520{
6521 struct mgmt_ev_new_long_term_key ev;
6522
6523 memset(&ev, 0, sizeof(ev));
6524
Marcel Holtmann5192d302014-02-19 17:11:58 -08006525 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006526 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006527 * to store long term keys. Their addresses will change the
6528 * next time around.
6529 *
6530 * Only when a remote device provides an identity address
6531 * make sure the long term key is stored. If the remote
6532 * identity is known, the long term keys are internally
6533 * mapped to the identity address. So allow static random
6534 * and public addresses here.
6535 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006536 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6537 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6538 ev.store_hint = 0x00;
6539 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006540 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006541
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006542 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006543 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006544 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006545 ev.key.enc_size = key->enc_size;
6546 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006547 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006548
Johan Hedberg2ceba532014-06-16 19:25:16 +03006549 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006550 ev.key.master = 1;
6551
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006552 /* Make sure we copy only the significant bytes based on the
6553 * encryption key size, and set the rest of the value to zeroes.
6554 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006555 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006556 memset(ev.key.val + key->enc_size, 0,
6557 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006558
Marcel Holtmann083368f2013-10-15 14:26:29 -07006559 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006560}
6561
Johan Hedbergcad20c22015-10-12 13:36:19 +02006562void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006563{
6564 struct mgmt_ev_new_irk ev;
6565
6566 memset(&ev, 0, sizeof(ev));
6567
Johan Hedbergcad20c22015-10-12 13:36:19 +02006568 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006569
Johan Hedberg95fbac82014-02-19 15:18:31 +02006570 bacpy(&ev.rpa, &irk->rpa);
6571 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6572 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6573 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6574
6575 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6576}
6577
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006578void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6579 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006580{
6581 struct mgmt_ev_new_csrk ev;
6582
6583 memset(&ev, 0, sizeof(ev));
6584
6585 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006586 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006587 * to store signature resolving keys. Their addresses will change
6588 * the next time around.
6589 *
6590 * Only when a remote device provides an identity address
6591 * make sure the signature resolving key is stored. So allow
6592 * static random and public addresses here.
6593 */
6594 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6595 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6596 ev.store_hint = 0x00;
6597 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006598 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006599
6600 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6601 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006602 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006603 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6604
6605 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6606}
6607
Andre Guedesffb5a8272014-07-01 18:10:11 -03006608void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006609 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6610 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006611{
6612 struct mgmt_ev_new_conn_param ev;
6613
Johan Hedbergc103aea2014-07-02 17:37:34 +03006614 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6615 return;
6616
Andre Guedesffb5a8272014-07-01 18:10:11 -03006617 memset(&ev, 0, sizeof(ev));
6618 bacpy(&ev.addr.bdaddr, bdaddr);
6619 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006620 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006621 ev.min_interval = cpu_to_le16(min_interval);
6622 ev.max_interval = cpu_to_le16(max_interval);
6623 ev.latency = cpu_to_le16(latency);
6624 ev.timeout = cpu_to_le16(timeout);
6625
6626 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6627}
6628
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006629void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6630 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006631{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006632 char buf[512];
6633 struct mgmt_ev_device_connected *ev = (void *) buf;
6634 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006635
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006636 bacpy(&ev->addr.bdaddr, &conn->dst);
6637 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006638
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006639 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006640
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006641 /* We must ensure that the EIR Data fields are ordered and
6642 * unique. Keep it simple for now and avoid the problem by not
6643 * adding any BR/EDR data to the LE adv.
6644 */
6645 if (conn->le_adv_data_len > 0) {
6646 memcpy(&ev->eir[eir_len],
6647 conn->le_adv_data, conn->le_adv_data_len);
6648 eir_len = conn->le_adv_data_len;
6649 } else {
6650 if (name_len > 0)
6651 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6652 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006653
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006654 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006655 eir_len = eir_append_data(ev->eir, eir_len,
6656 EIR_CLASS_OF_DEV,
6657 conn->dev_class, 3);
6658 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006659
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006660 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006661
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006662 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6663 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006664}
6665
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006666static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006667{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006668 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006669
Johan Hedbergf5818c22014-12-05 13:36:02 +02006670 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006671
6672 *sk = cmd->sk;
6673 sock_hold(*sk);
6674
Johan Hedberga664b5b2011-02-19 12:06:02 -03006675 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006676}
6677
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006678static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006679{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006680 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006681 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006682
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006683 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6684
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006685 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006686 mgmt_pending_remove(cmd);
6687}
6688
Johan Hedberg84c61d92014-08-01 11:13:30 +03006689bool mgmt_powering_down(struct hci_dev *hdev)
6690{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006691 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006692 struct mgmt_mode *cp;
6693
Johan Hedberg333ae952015-03-17 13:48:47 +02006694 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006695 if (!cmd)
6696 return false;
6697
6698 cp = cmd->param;
6699 if (!cp->val)
6700 return true;
6701
6702 return false;
6703}
6704
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006705void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006706 u8 link_type, u8 addr_type, u8 reason,
6707 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006708{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006709 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006710 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006711
Johan Hedberg84c61d92014-08-01 11:13:30 +03006712 /* The connection is still in hci_conn_hash so test for 1
6713 * instead of 0 to know if this is the last one.
6714 */
6715 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6716 cancel_delayed_work(&hdev->power_off);
6717 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006718 }
6719
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006720 if (!mgmt_connected)
6721 return;
6722
Andre Guedes57eb7762013-10-30 19:01:41 -03006723 if (link_type != ACL_LINK && link_type != LE_LINK)
6724 return;
6725
Johan Hedberg744cf192011-11-08 20:40:14 +02006726 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006727
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006728 bacpy(&ev.addr.bdaddr, bdaddr);
6729 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6730 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006731
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006732 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006733
6734 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006735 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006736
Johan Hedberg124f6e32012-02-09 13:50:12 +02006737 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006738 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006739}
6740
Marcel Holtmann78929242013-10-06 23:55:47 -07006741void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6742 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006743{
Andre Guedes3655bba2013-10-30 19:01:40 -03006744 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6745 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006746 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006747
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006748 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6749 hdev);
6750
Johan Hedberg333ae952015-03-17 13:48:47 +02006751 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006752 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006753 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006754
Andre Guedes3655bba2013-10-30 19:01:40 -03006755 cp = cmd->param;
6756
6757 if (bacmp(bdaddr, &cp->addr.bdaddr))
6758 return;
6759
6760 if (cp->addr.type != bdaddr_type)
6761 return;
6762
Johan Hedbergf5818c22014-12-05 13:36:02 +02006763 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006764 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006765}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006766
Marcel Holtmann445608d2013-10-06 23:55:48 -07006767void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6768 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006769{
6770 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006771
Johan Hedberg84c61d92014-08-01 11:13:30 +03006772 /* The connection is still in hci_conn_hash so test for 1
6773 * instead of 0 to know if this is the last one.
6774 */
6775 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6776 cancel_delayed_work(&hdev->power_off);
6777 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006778 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006779
Johan Hedberg4c659c32011-11-07 23:13:39 +02006780 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006781 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006782 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006783
Marcel Holtmann445608d2013-10-06 23:55:48 -07006784 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006785}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006786
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006787void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006788{
6789 struct mgmt_ev_pin_code_request ev;
6790
Johan Hedbergd8457692012-02-17 14:24:57 +02006791 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006792 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006793 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006794
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006795 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006796}
6797
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006798void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6799 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006800{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006801 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006802
Johan Hedberg333ae952015-03-17 13:48:47 +02006803 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006804 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006805 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006806
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006807 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006808 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006809}
6810
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006811void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6812 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006813{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006814 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006815
Johan Hedberg333ae952015-03-17 13:48:47 +02006816 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006817 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006818 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006819
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006820 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006821 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006822}
Johan Hedberga5c29682011-02-19 12:05:57 -03006823
Johan Hedberg744cf192011-11-08 20:40:14 +02006824int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006825 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006826 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006827{
6828 struct mgmt_ev_user_confirm_request ev;
6829
Johan Hedberg744cf192011-11-08 20:40:14 +02006830 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006831
Johan Hedberg272d90d2012-02-09 15:26:12 +02006832 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006833 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006834 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006835 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006836
Johan Hedberg744cf192011-11-08 20:40:14 +02006837 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006838 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006839}
6840
Johan Hedberg272d90d2012-02-09 15:26:12 +02006841int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006842 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08006843{
6844 struct mgmt_ev_user_passkey_request ev;
6845
6846 BT_DBG("%s", hdev->name);
6847
Johan Hedberg272d90d2012-02-09 15:26:12 +02006848 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006849 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08006850
6851 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006852 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08006853}
6854
Brian Gix0df4c182011-11-16 13:53:13 -08006855static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006856 u8 link_type, u8 addr_type, u8 status,
6857 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03006858{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006859 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03006860
Johan Hedberg333ae952015-03-17 13:48:47 +02006861 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03006862 if (!cmd)
6863 return -ENOENT;
6864
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006865 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006866 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03006867
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006868 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03006869}
6870
Johan Hedberg744cf192011-11-08 20:40:14 +02006871int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006872 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006873{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006874 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006875 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006876}
6877
Johan Hedberg272d90d2012-02-09 15:26:12 +02006878int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006879 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006880{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006881 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006882 status,
6883 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006884}
Johan Hedberg2a611692011-02-19 12:06:00 -03006885
Brian Gix604086b2011-11-23 08:28:33 -08006886int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006887 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006888{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006889 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006890 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006891}
6892
Johan Hedberg272d90d2012-02-09 15:26:12 +02006893int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006894 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006895{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006896 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006897 status,
6898 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006899}
6900
Johan Hedberg92a25252012-09-06 18:39:26 +03006901int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
6902 u8 link_type, u8 addr_type, u32 passkey,
6903 u8 entered)
6904{
6905 struct mgmt_ev_passkey_notify ev;
6906
6907 BT_DBG("%s", hdev->name);
6908
6909 bacpy(&ev.addr.bdaddr, bdaddr);
6910 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6911 ev.passkey = __cpu_to_le32(passkey);
6912 ev.entered = entered;
6913
6914 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
6915}
6916
Johan Hedberge1e930f2014-09-08 17:09:49 -07006917void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03006918{
6919 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006920 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07006921 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03006922
Johan Hedberge1e930f2014-09-08 17:09:49 -07006923 bacpy(&ev.addr.bdaddr, &conn->dst);
6924 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
6925 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03006926
Johan Hedberge1e930f2014-09-08 17:09:49 -07006927 cmd = find_pairing(conn);
6928
6929 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
6930 cmd ? cmd->sk : NULL);
6931
Johan Hedberga511b352014-12-11 21:45:45 +02006932 if (cmd) {
6933 cmd->cmd_complete(cmd, status);
6934 mgmt_pending_remove(cmd);
6935 }
Johan Hedberg2a611692011-02-19 12:06:00 -03006936}
Johan Hedbergb312b1612011-03-16 14:29:37 +02006937
Marcel Holtmann464996a2013-10-15 14:26:24 -07006938void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006939{
6940 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07006941 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006942
6943 if (status) {
6944 u8 mgmt_err = mgmt_status(status);
6945 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006946 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07006947 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006948 }
6949
Marcel Holtmann464996a2013-10-15 14:26:24 -07006950 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07006951 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07006952 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006953 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02006954
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006955 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006956 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006957
Johan Hedberg47990ea2012-02-22 11:58:37 +02006958 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07006959 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006960
6961 if (match.sk)
6962 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006963}
6964
Johan Hedberg890ea892013-03-15 17:06:52 -05006965static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02006966{
Johan Hedberg890ea892013-03-15 17:06:52 -05006967 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02006968 struct hci_cp_write_eir cp;
6969
Johan Hedberg976eb202012-10-24 21:12:01 +03006970 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006971 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02006972
Johan Hedbergc80da272012-02-22 15:38:48 +02006973 memset(hdev->eir, 0, sizeof(hdev->eir));
6974
Johan Hedbergcacaf522012-02-21 00:52:42 +02006975 memset(&cp, 0, sizeof(cp));
6976
Johan Hedberg890ea892013-03-15 17:06:52 -05006977 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02006978}
6979
Marcel Holtmann3e248562013-10-15 14:26:25 -07006980void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02006981{
6982 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05006983 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02006984 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02006985
6986 if (status) {
6987 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02006988
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006989 if (enable && hci_dev_test_and_clear_flag(hdev,
6990 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006991 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07006992 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07006993 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02006994
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006995 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
6996 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07006997 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02006998 }
6999
7000 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007001 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007002 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007003 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007004 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007005 changed = hci_dev_test_and_clear_flag(hdev,
7006 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007007 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007008 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007009 }
7010
7011 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7012
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007013 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007014 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007015
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007016 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007017 sock_put(match.sk);
7018
Johan Hedberg890ea892013-03-15 17:06:52 -05007019 hci_req_init(&req, hdev);
7020
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007021 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7022 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007023 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7024 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007025 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007026 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007027 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007028 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007029
7030 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007031}
7032
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007033static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007034{
7035 struct cmd_lookup *match = data;
7036
Johan Hedberg90e70452012-02-23 23:09:40 +02007037 if (match->sk == NULL) {
7038 match->sk = cmd->sk;
7039 sock_hold(match->sk);
7040 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007041}
7042
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007043void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7044 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007045{
Johan Hedberg90e70452012-02-23 23:09:40 +02007046 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007047
Johan Hedberg92da6092013-03-15 17:06:55 -05007048 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7049 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7050 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007051
7052 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007053 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7054 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007055
7056 if (match.sk)
7057 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007058}
7059
Marcel Holtmann7667da32013-10-15 14:26:27 -07007060void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007061{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007062 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007063 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007064
Johan Hedberg13928972013-03-15 17:07:00 -05007065 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007066 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007067
7068 memset(&ev, 0, sizeof(ev));
7069 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007070 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007071
Johan Hedberg333ae952015-03-17 13:48:47 +02007072 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007073 if (!cmd) {
7074 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007075
Johan Hedberg13928972013-03-15 17:07:00 -05007076 /* If this is a HCI command related to powering on the
7077 * HCI dev don't send any mgmt signals.
7078 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007079 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007080 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007081 }
7082
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007083 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7084 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007085}
Szymon Jancc35938b2011-03-22 13:12:21 +01007086
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007087static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7088{
7089 int i;
7090
7091 for (i = 0; i < uuid_count; i++) {
7092 if (!memcmp(uuid, uuids[i], 16))
7093 return true;
7094 }
7095
7096 return false;
7097}
7098
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007099static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7100{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007101 u16 parsed = 0;
7102
7103 while (parsed < eir_len) {
7104 u8 field_len = eir[0];
7105 u8 uuid[16];
7106 int i;
7107
7108 if (field_len == 0)
7109 break;
7110
7111 if (eir_len - parsed < field_len + 1)
7112 break;
7113
7114 switch (eir[1]) {
7115 case EIR_UUID16_ALL:
7116 case EIR_UUID16_SOME:
7117 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007118 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007119 uuid[13] = eir[i + 3];
7120 uuid[12] = eir[i + 2];
7121 if (has_uuid(uuid, uuid_count, uuids))
7122 return true;
7123 }
7124 break;
7125 case EIR_UUID32_ALL:
7126 case EIR_UUID32_SOME:
7127 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007128 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007129 uuid[15] = eir[i + 5];
7130 uuid[14] = eir[i + 4];
7131 uuid[13] = eir[i + 3];
7132 uuid[12] = eir[i + 2];
7133 if (has_uuid(uuid, uuid_count, uuids))
7134 return true;
7135 }
7136 break;
7137 case EIR_UUID128_ALL:
7138 case EIR_UUID128_SOME:
7139 for (i = 0; i + 17 <= field_len; i += 16) {
7140 memcpy(uuid, eir + i + 2, 16);
7141 if (has_uuid(uuid, uuid_count, uuids))
7142 return true;
7143 }
7144 break;
7145 }
7146
7147 parsed += field_len + 1;
7148 eir += field_len + 1;
7149 }
7150
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007151 return false;
7152}
7153
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007154static void restart_le_scan(struct hci_dev *hdev)
7155{
7156 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007157 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007158 return;
7159
7160 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7161 hdev->discovery.scan_start +
7162 hdev->discovery.scan_duration))
7163 return;
7164
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007165 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007166 DISCOV_LE_RESTART_DELAY);
7167}
7168
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007169static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7170 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7171{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007172 /* If a RSSI threshold has been specified, and
7173 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7174 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7175 * is set, let it through for further processing, as we might need to
7176 * restart the scan.
7177 *
7178 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7179 * the results are also dropped.
7180 */
7181 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7182 (rssi == HCI_RSSI_INVALID ||
7183 (rssi < hdev->discovery.rssi &&
7184 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7185 return false;
7186
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007187 if (hdev->discovery.uuid_count != 0) {
7188 /* If a list of UUIDs is provided in filter, results with no
7189 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007190 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007191 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7192 hdev->discovery.uuids) &&
7193 !eir_has_uuids(scan_rsp, scan_rsp_len,
7194 hdev->discovery.uuid_count,
7195 hdev->discovery.uuids))
7196 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007197 }
7198
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007199 /* If duplicate filtering does not report RSSI changes, then restart
7200 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007201 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007202 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7203 restart_le_scan(hdev);
7204
7205 /* Validate RSSI value against the RSSI threshold once more. */
7206 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7207 rssi < hdev->discovery.rssi)
7208 return false;
7209 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007210
7211 return true;
7212}
7213
Marcel Holtmann901801b2013-10-06 23:55:51 -07007214void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007215 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7216 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007217{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007218 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007219 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007220 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007221
Johan Hedberg75ce2082014-07-02 22:42:01 +03007222 /* Don't send events for a non-kernel initiated discovery. With
7223 * LE one exception is if we have pend_le_reports > 0 in which
7224 * case we're doing passive scanning and want these events.
7225 */
7226 if (!hci_discovery_active(hdev)) {
7227 if (link_type == ACL_LINK)
7228 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007229 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007230 return;
7231 }
Andre Guedes12602d02013-04-30 15:29:40 -03007232
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007233 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007234 /* We are using service discovery */
7235 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7236 scan_rsp_len))
7237 return;
7238 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007239
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007240 /* Make sure that the buffer is big enough. The 5 extra bytes
7241 * are for the potential CoD field.
7242 */
7243 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007244 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007245
Johan Hedberg1dc06092012-01-15 21:01:23 +02007246 memset(buf, 0, sizeof(buf));
7247
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007248 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7249 * RSSI value was reported as 0 when not available. This behavior
7250 * is kept when using device discovery. This is required for full
7251 * backwards compatibility with the API.
7252 *
7253 * However when using service discovery, the value 127 will be
7254 * returned when the RSSI is not available.
7255 */
Szymon Janc91200e92015-01-22 16:57:05 +01007256 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7257 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007258 rssi = 0;
7259
Johan Hedberg841c5642014-07-07 12:45:54 +03007260 bacpy(&ev->addr.bdaddr, bdaddr);
7261 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007262 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007263 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007264
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007265 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007266 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007267 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007268
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007269 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7270 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007271 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007272 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007273
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007274 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007275 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007276 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007277
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007278 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7279 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007280
Marcel Holtmann901801b2013-10-06 23:55:51 -07007281 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007282}
Johan Hedberga88a9652011-03-30 13:18:12 +03007283
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007284void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7285 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007286{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007287 struct mgmt_ev_device_found *ev;
7288 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7289 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007290
Johan Hedbergb644ba32012-01-17 21:48:47 +02007291 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007292
Johan Hedbergb644ba32012-01-17 21:48:47 +02007293 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007294
Johan Hedbergb644ba32012-01-17 21:48:47 +02007295 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007296 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007297 ev->rssi = rssi;
7298
7299 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007300 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007301
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007302 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007303
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007304 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007305}
Johan Hedberg314b2382011-04-27 10:29:57 -04007306
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007307void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007308{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007309 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007310
Andre Guedes343fb142011-11-22 17:14:19 -03007311 BT_DBG("%s discovering %u", hdev->name, discovering);
7312
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007313 memset(&ev, 0, sizeof(ev));
7314 ev.type = hdev->discovery.type;
7315 ev.discovering = discovering;
7316
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007317 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007318}
Antti Julku5e762442011-08-25 16:48:02 +03007319
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007320static struct hci_mgmt_chan chan = {
7321 .channel = HCI_CHANNEL_CONTROL,
7322 .handler_count = ARRAY_SIZE(mgmt_handlers),
7323 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007324 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007325};
7326
7327int mgmt_init(void)
7328{
7329 return hci_mgmt_chan_register(&chan);
7330}
7331
7332void mgmt_exit(void)
7333{
7334 hci_mgmt_chan_unregister(&chan);
7335}