blob: 29b3bb70ae9f39f48d6cc75bfcb88d6f2c695b6e [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 Holtmannedd3896b2014-07-02 21:30:55 +0200136 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200137 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700138 MGMT_EV_EXT_INDEX_ADDED,
139 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700140 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700141 MGMT_EV_ADVERTISING_ADDED,
142 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200143};
144
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700145static const u16 mgmt_untrusted_commands[] = {
146 MGMT_OP_READ_INDEX_LIST,
147 MGMT_OP_READ_INFO,
148 MGMT_OP_READ_UNCONF_INDEX_LIST,
149 MGMT_OP_READ_CONFIG_INFO,
150 MGMT_OP_READ_EXT_INDEX_LIST,
151};
152
153static const u16 mgmt_untrusted_events[] = {
154 MGMT_EV_INDEX_ADDED,
155 MGMT_EV_INDEX_REMOVED,
156 MGMT_EV_NEW_SETTINGS,
157 MGMT_EV_CLASS_OF_DEV_CHANGED,
158 MGMT_EV_LOCAL_NAME_CHANGED,
159 MGMT_EV_UNCONF_INDEX_ADDED,
160 MGMT_EV_UNCONF_INDEX_REMOVED,
161 MGMT_EV_NEW_CONFIG_OPTIONS,
162 MGMT_EV_EXT_INDEX_ADDED,
163 MGMT_EV_EXT_INDEX_REMOVED,
164};
165
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800166#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200167
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200168#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
169 "\x00\x00\x00\x00\x00\x00\x00\x00"
170
Johan Hedbergca69b792011-11-11 18:10:00 +0200171/* HCI to MGMT error code conversion table */
172static u8 mgmt_status_table[] = {
173 MGMT_STATUS_SUCCESS,
174 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
175 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
176 MGMT_STATUS_FAILED, /* Hardware Failure */
177 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
178 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200179 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200180 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
181 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
182 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
184 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
185 MGMT_STATUS_BUSY, /* Command Disallowed */
186 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
187 MGMT_STATUS_REJECTED, /* Rejected Security */
188 MGMT_STATUS_REJECTED, /* Rejected Personal */
189 MGMT_STATUS_TIMEOUT, /* Host Timeout */
190 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
191 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
192 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
193 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
194 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
195 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
196 MGMT_STATUS_BUSY, /* Repeated Attempts */
197 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
198 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
199 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
200 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
201 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
202 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
203 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
204 MGMT_STATUS_FAILED, /* Unspecified Error */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
206 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
207 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
208 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
209 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
210 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
211 MGMT_STATUS_FAILED, /* Unit Link Key Used */
212 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
213 MGMT_STATUS_TIMEOUT, /* Instant Passed */
214 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
215 MGMT_STATUS_FAILED, /* Transaction Collision */
216 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
217 MGMT_STATUS_REJECTED, /* QoS Rejected */
218 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
219 MGMT_STATUS_REJECTED, /* Insufficient Security */
220 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
221 MGMT_STATUS_BUSY, /* Role Switch Pending */
222 MGMT_STATUS_FAILED, /* Slot Violation */
223 MGMT_STATUS_FAILED, /* Role Switch Failed */
224 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
225 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
226 MGMT_STATUS_BUSY, /* Host Busy Pairing */
227 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
228 MGMT_STATUS_BUSY, /* Controller Busy */
229 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
230 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
231 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
232 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
233 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
234};
235
236static u8 mgmt_status(u8 hci_status)
237{
238 if (hci_status < ARRAY_SIZE(mgmt_status_table))
239 return mgmt_status_table[hci_status];
240
241 return MGMT_STATUS_FAILED;
242}
243
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700244static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
245 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700246{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700247 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
248 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700249}
250
Marcel Holtmann72000df2015-03-16 16:11:21 -0700251static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
252 u16 len, int flag, struct sock *skip_sk)
253{
254 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
255 flag, skip_sk);
256}
257
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700258static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
259 u16 len, struct sock *skip_sk)
260{
261 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
262 HCI_MGMT_GENERIC_EVENTS, skip_sk);
263}
264
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200265static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
266 struct sock *skip_sk)
267{
268 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700269 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200270}
271
Johan Hedberg85813a72015-10-21 18:02:59 +0300272static u8 le_addr_type(u8 mgmt_addr_type)
273{
274 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
275 return ADDR_LE_DEV_PUBLIC;
276 else
277 return ADDR_LE_DEV_RANDOM;
278}
279
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300280static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
281 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200282{
283 struct mgmt_rp_read_version rp;
284
285 BT_DBG("sock %p", sk);
286
287 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700288 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200289
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200290 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
291 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200292}
293
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300294static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
295 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296{
297 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700298 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200299 size_t rp_size;
300 int i, err;
301
302 BT_DBG("sock %p", sk);
303
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
305 num_commands = ARRAY_SIZE(mgmt_commands);
306 num_events = ARRAY_SIZE(mgmt_events);
307 } else {
308 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
309 num_events = ARRAY_SIZE(mgmt_untrusted_events);
310 }
311
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
313
314 rp = kmalloc(rp_size, GFP_KERNEL);
315 if (!rp)
316 return -ENOMEM;
317
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700318 rp->num_commands = cpu_to_le16(num_commands);
319 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700321 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
322 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200323
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700324 for (i = 0; i < num_commands; i++, opcode++)
325 put_unaligned_le16(mgmt_commands[i], opcode);
326
327 for (i = 0; i < num_events; i++, opcode++)
328 put_unaligned_le16(mgmt_events[i], opcode);
329 } else {
330 __le16 *opcode = rp->opcodes;
331
332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
337 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200338
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200339 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
340 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200341 kfree(rp);
342
343 return err;
344}
345
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300346static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
347 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200351 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
355 BT_DBG("sock %p", sk);
356
357 read_lock(&hci_dev_list_lock);
358
359 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300360 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200361 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700362 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700363 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364 }
365
Johan Hedberga38528f2011-01-22 06:46:43 +0200366 rp_len = sizeof(*rp) + (2 * count);
367 rp = kmalloc(rp_len, GFP_ATOMIC);
368 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100369 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100371 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372
Johan Hedberg476e44c2012-10-19 20:10:46 +0300373 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200374 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700375 if (hci_dev_test_flag(d, HCI_SETUP) ||
376 hci_dev_test_flag(d, HCI_CONFIG) ||
377 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200378 continue;
379
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200380 /* Devices marked as raw-only are neither configured
381 * nor unconfigured controllers.
382 */
383 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700387 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700388 rp->index[count++] = cpu_to_le16(d->id);
389 BT_DBG("Added hci%u", d->id);
390 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391 }
392
Johan Hedberg476e44c2012-10-19 20:10:46 +0300393 rp->num_controllers = cpu_to_le16(count);
394 rp_len = sizeof(*rp) + (2 * count);
395
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 read_unlock(&hci_dev_list_lock);
397
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200398 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
399 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400
Johan Hedberga38528f2011-01-22 06:46:43 +0200401 kfree(rp);
402
403 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404}
405
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200406static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
407 void *data, u16 data_len)
408{
409 struct mgmt_rp_read_unconf_index_list *rp;
410 struct hci_dev *d;
411 size_t rp_len;
412 u16 count;
413 int err;
414
415 BT_DBG("sock %p", sk);
416
417 read_lock(&hci_dev_list_lock);
418
419 count = 0;
420 list_for_each_entry(d, &hci_dev_list, list) {
421 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700422 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200423 count++;
424 }
425
426 rp_len = sizeof(*rp) + (2 * count);
427 rp = kmalloc(rp_len, GFP_ATOMIC);
428 if (!rp) {
429 read_unlock(&hci_dev_list_lock);
430 return -ENOMEM;
431 }
432
433 count = 0;
434 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700435 if (hci_dev_test_flag(d, HCI_SETUP) ||
436 hci_dev_test_flag(d, HCI_CONFIG) ||
437 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438 continue;
439
440 /* Devices marked as raw-only are neither configured
441 * nor unconfigured controllers.
442 */
443 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
444 continue;
445
446 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700447 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448 rp->index[count++] = cpu_to_le16(d->id);
449 BT_DBG("Added hci%u", d->id);
450 }
451 }
452
453 rp->num_controllers = cpu_to_le16(count);
454 rp_len = sizeof(*rp) + (2 * count);
455
456 read_unlock(&hci_dev_list_lock);
457
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200458 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
459 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200460
461 kfree(rp);
462
463 return err;
464}
465
Marcel Holtmann96f14742015-03-14 19:27:57 -0700466static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
467 void *data, u16 data_len)
468{
469 struct mgmt_rp_read_ext_index_list *rp;
470 struct hci_dev *d;
471 size_t rp_len;
472 u16 count;
473 int err;
474
475 BT_DBG("sock %p", sk);
476
477 read_lock(&hci_dev_list_lock);
478
479 count = 0;
480 list_for_each_entry(d, &hci_dev_list, list) {
481 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
482 count++;
483 }
484
485 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
486 rp = kmalloc(rp_len, GFP_ATOMIC);
487 if (!rp) {
488 read_unlock(&hci_dev_list_lock);
489 return -ENOMEM;
490 }
491
492 count = 0;
493 list_for_each_entry(d, &hci_dev_list, list) {
494 if (hci_dev_test_flag(d, HCI_SETUP) ||
495 hci_dev_test_flag(d, HCI_CONFIG) ||
496 hci_dev_test_flag(d, HCI_USER_CHANNEL))
497 continue;
498
499 /* Devices marked as raw-only are neither configured
500 * nor unconfigured controllers.
501 */
502 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
503 continue;
504
505 if (d->dev_type == HCI_BREDR) {
506 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
507 rp->entry[count].type = 0x01;
508 else
509 rp->entry[count].type = 0x00;
510 } else if (d->dev_type == HCI_AMP) {
511 rp->entry[count].type = 0x02;
512 } else {
513 continue;
514 }
515
516 rp->entry[count].bus = d->bus;
517 rp->entry[count++].index = cpu_to_le16(d->id);
518 BT_DBG("Added hci%u", d->id);
519 }
520
521 rp->num_controllers = cpu_to_le16(count);
522 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
523
524 read_unlock(&hci_dev_list_lock);
525
526 /* If this command is called at least once, then all the
527 * default index and unconfigured index events are disabled
528 * and from now on only extended index events are used.
529 */
530 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
531 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
532 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
533
534 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
535 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
536
537 kfree(rp);
538
539 return err;
540}
541
Marcel Holtmanndbece372014-07-04 18:11:55 +0200542static bool is_configured(struct hci_dev *hdev)
543{
544 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700545 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200546 return false;
547
548 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
549 !bacmp(&hdev->public_addr, BDADDR_ANY))
550 return false;
551
552 return true;
553}
554
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200555static __le32 get_missing_options(struct hci_dev *hdev)
556{
557 u32 options = 0;
558
Marcel Holtmanndbece372014-07-04 18:11:55 +0200559 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700560 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200561 options |= MGMT_OPTION_EXTERNAL_CONFIG;
562
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200563 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
564 !bacmp(&hdev->public_addr, BDADDR_ANY))
565 options |= MGMT_OPTION_PUBLIC_ADDRESS;
566
567 return cpu_to_le32(options);
568}
569
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200570static int new_options(struct hci_dev *hdev, struct sock *skip)
571{
572 __le32 options = get_missing_options(hdev);
573
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700574 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
575 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576}
577
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
579{
580 __le32 options = get_missing_options(hdev);
581
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200582 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
583 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584}
585
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200586static int read_config_info(struct sock *sk, struct hci_dev *hdev,
587 void *data, u16 data_len)
588{
589 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200590 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591
592 BT_DBG("sock %p %s", sk, hdev->name);
593
594 hci_dev_lock(hdev);
595
596 memset(&rp, 0, sizeof(rp));
597 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
600 options |= MGMT_OPTION_EXTERNAL_CONFIG;
601
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200602 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603 options |= MGMT_OPTION_PUBLIC_ADDRESS;
604
605 rp.supported_options = cpu_to_le32(options);
606 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607
608 hci_dev_unlock(hdev);
609
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
611 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612}
613
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200614static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200615{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200617
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300619 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800620 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300621 settings |= MGMT_SETTING_CONNECTABLE;
622 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Andre Guedesed3fa312012-07-24 15:03:46 -0300624 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500625 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
626 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627 settings |= MGMT_SETTING_BREDR;
628 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700629
630 if (lmp_ssp_capable(hdev)) {
631 settings |= MGMT_SETTING_SSP;
632 settings |= MGMT_SETTING_HS;
633 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800634
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800635 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800636 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700637 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100638
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300639 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200640 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300641 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300642 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200643 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800644 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300645 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200646
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200647 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
648 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200649 settings |= MGMT_SETTING_CONFIGURATION;
650
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651 return settings;
652}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200653
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200654static u32 get_current_settings(struct hci_dev *hdev)
655{
656 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200657
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200658 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100659 settings |= MGMT_SETTING_POWERED;
660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662 settings |= MGMT_SETTING_CONNECTABLE;
663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700664 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500665 settings |= MGMT_SETTING_FAST_CONNECTABLE;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_DISCOVERABLE;
669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300671 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_BREDR;
675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200683 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200686 settings |= MGMT_SETTING_HS;
687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300689 settings |= MGMT_SETTING_ADVERTISING;
690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700691 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800692 settings |= MGMT_SETTING_SECURE_CONN;
693
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700694 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800695 settings |= MGMT_SETTING_DEBUG_KEYS;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200698 settings |= MGMT_SETTING_PRIVACY;
699
Marcel Holtmann93690c22015-03-06 10:11:21 -0800700 /* The current setting for static address has two purposes. The
701 * first is to indicate if the static address will be used and
702 * the second is to indicate if it is actually set.
703 *
704 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700705 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800706 * address is actually used decides if the flag is set or not.
707 *
708 * For single mode LE only controllers and dual-mode controllers
709 * with BR/EDR disabled, the existence of the static address will
710 * be evaluated.
711 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700712 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700713 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800714 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
715 if (bacmp(&hdev->static_addr, BDADDR_ANY))
716 settings |= MGMT_SETTING_STATIC_ADDRESS;
717 }
718
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200720}
721
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300722#define PNP_INFO_SVCLASS_ID 0x1200
723
Johan Hedberg213202e2013-01-27 00:31:33 +0200724static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
725{
726 u8 *ptr = data, *uuids_start = NULL;
727 struct bt_uuid *uuid;
728
729 if (len < 4)
730 return ptr;
731
732 list_for_each_entry(uuid, &hdev->uuids, list) {
733 u16 uuid16;
734
735 if (uuid->size != 16)
736 continue;
737
738 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
739 if (uuid16 < 0x1100)
740 continue;
741
742 if (uuid16 == PNP_INFO_SVCLASS_ID)
743 continue;
744
745 if (!uuids_start) {
746 uuids_start = ptr;
747 uuids_start[0] = 1;
748 uuids_start[1] = EIR_UUID16_ALL;
749 ptr += 2;
750 }
751
752 /* Stop if not enough space to put next UUID */
753 if ((ptr - data) + sizeof(u16) > len) {
754 uuids_start[1] = EIR_UUID16_SOME;
755 break;
756 }
757
758 *ptr++ = (uuid16 & 0x00ff);
759 *ptr++ = (uuid16 & 0xff00) >> 8;
760 uuids_start[0] += sizeof(uuid16);
761 }
762
763 return ptr;
764}
765
Johan Hedbergcdf19632013-01-27 00:31:34 +0200766static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
767{
768 u8 *ptr = data, *uuids_start = NULL;
769 struct bt_uuid *uuid;
770
771 if (len < 6)
772 return ptr;
773
774 list_for_each_entry(uuid, &hdev->uuids, list) {
775 if (uuid->size != 32)
776 continue;
777
778 if (!uuids_start) {
779 uuids_start = ptr;
780 uuids_start[0] = 1;
781 uuids_start[1] = EIR_UUID32_ALL;
782 ptr += 2;
783 }
784
785 /* Stop if not enough space to put next UUID */
786 if ((ptr - data) + sizeof(u32) > len) {
787 uuids_start[1] = EIR_UUID32_SOME;
788 break;
789 }
790
791 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
792 ptr += sizeof(u32);
793 uuids_start[0] += sizeof(u32);
794 }
795
796 return ptr;
797}
798
Johan Hedbergc00d5752013-01-27 00:31:35 +0200799static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
800{
801 u8 *ptr = data, *uuids_start = NULL;
802 struct bt_uuid *uuid;
803
804 if (len < 18)
805 return ptr;
806
807 list_for_each_entry(uuid, &hdev->uuids, list) {
808 if (uuid->size != 128)
809 continue;
810
811 if (!uuids_start) {
812 uuids_start = ptr;
813 uuids_start[0] = 1;
814 uuids_start[1] = EIR_UUID128_ALL;
815 ptr += 2;
816 }
817
818 /* Stop if not enough space to put next UUID */
819 if ((ptr - data) + 16 > len) {
820 uuids_start[1] = EIR_UUID128_SOME;
821 break;
822 }
823
824 memcpy(ptr, uuid->uuid, 16);
825 ptr += 16;
826 uuids_start[0] += 16;
827 }
828
829 return ptr;
830}
831
Johan Hedberg333ae952015-03-17 13:48:47 +0200832static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
833{
834 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
835}
836
Johan Hedberg333ae952015-03-17 13:48:47 +0200837static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
838 struct hci_dev *hdev,
839 const void *data)
840{
841 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
842}
843
Johan Hedbergf2252572015-11-18 12:49:20 +0200844u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300845{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200846 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300847
848 /* If there's a pending mgmt command the flags will not yet have
849 * their final values, so check for this first.
850 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200851 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300852 if (cmd) {
853 struct mgmt_mode *cp = cmd->param;
854 if (cp->val == 0x01)
855 return LE_AD_GENERAL;
856 else if (cp->val == 0x02)
857 return LE_AD_LIMITED;
858 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700859 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300860 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700861 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300862 return LE_AD_GENERAL;
863 }
864
865 return 0;
866}
867
Johan Hedbergf2252572015-11-18 12:49:20 +0200868bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700869{
870 struct mgmt_pending_cmd *cmd;
871
872 /* If there's a pending mgmt command the flag will not yet have
873 * it's final value, so check for this first.
874 */
875 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
876 if (cmd) {
877 struct mgmt_mode *cp = cmd->param;
878
879 return cp->val;
880 }
881
882 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
883}
884
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300885static void create_eir(struct hci_dev *hdev, u8 *data)
886{
887 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300888 size_t name_len;
889
890 name_len = strlen(hdev->dev_name);
891
892 if (name_len > 0) {
893 /* EIR Data type */
894 if (name_len > 48) {
895 name_len = 48;
896 ptr[1] = EIR_NAME_SHORT;
897 } else
898 ptr[1] = EIR_NAME_COMPLETE;
899
900 /* EIR Data length */
901 ptr[0] = name_len + 1;
902
903 memcpy(ptr + 2, hdev->dev_name, name_len);
904
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300905 ptr += (name_len + 2);
906 }
907
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100908 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700909 ptr[0] = 2;
910 ptr[1] = EIR_TX_POWER;
911 ptr[2] = (u8) hdev->inq_tx_power;
912
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700913 ptr += 3;
914 }
915
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700916 if (hdev->devid_source > 0) {
917 ptr[0] = 9;
918 ptr[1] = EIR_DEVICE_ID;
919
920 put_unaligned_le16(hdev->devid_source, ptr + 2);
921 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
922 put_unaligned_le16(hdev->devid_product, ptr + 6);
923 put_unaligned_le16(hdev->devid_version, ptr + 8);
924
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700925 ptr += 10;
926 }
927
Johan Hedberg213202e2013-01-27 00:31:33 +0200928 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200929 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200930 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300931}
932
Johan Hedberg890ea892013-03-15 17:06:52 -0500933static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300934{
Johan Hedberg890ea892013-03-15 17:06:52 -0500935 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300936 struct hci_cp_write_eir cp;
937
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200938 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500939 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200940
Johan Hedberg976eb202012-10-24 21:12:01 +0300941 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500942 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300943
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700944 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -0500945 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300946
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700947 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -0500948 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300949
950 memset(&cp, 0, sizeof(cp));
951
952 create_eir(hdev, cp.data);
953
954 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500955 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300956
957 memcpy(hdev->eir, cp.data, sizeof(cp.data));
958
Johan Hedberg890ea892013-03-15 17:06:52 -0500959 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300960}
961
Johan Hedberg7d785252011-12-15 00:47:39 +0200962static void service_cache_off(struct work_struct *work)
963{
964 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300965 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500966 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200967
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700968 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200969 return;
970
Johan Hedberg890ea892013-03-15 17:06:52 -0500971 hci_req_init(&req, hdev);
972
Johan Hedberg7d785252011-12-15 00:47:39 +0200973 hci_dev_lock(hdev);
974
Johan Hedberg890ea892013-03-15 17:06:52 -0500975 update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200976 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200977
978 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500979
980 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200981}
982
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200983static void rpa_expired(struct work_struct *work)
984{
985 struct hci_dev *hdev = container_of(work, struct hci_dev,
986 rpa_expired.work);
987 struct hci_request req;
988
989 BT_DBG("");
990
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700991 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200992
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700993 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200994 return;
995
996 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200997 * controller happens in the hci_req_enable_advertising()
998 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200999 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001000 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001001 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001002 hci_req_run(&req, NULL);
1003}
1004
Johan Hedberg6a919082012-02-28 06:17:26 +02001005static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001006{
Marcel Holtmann238be782015-03-13 02:11:06 -07001007 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001008 return;
1009
Johan Hedberg4f87da82012-03-02 19:55:56 +02001010 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001011 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001012
Johan Hedberg4f87da82012-03-02 19:55:56 +02001013 /* Non-mgmt controlled devices get this bit set
1014 * implicitly so that pairing works for them, however
1015 * for mgmt we require user-space to explicitly enable
1016 * it
1017 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001018 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001019}
1020
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001021static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001022 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001023{
1024 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001026 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001029
Johan Hedberg03811012010-12-08 00:21:06 +02001030 memset(&rp, 0, sizeof(rp));
1031
Johan Hedberg03811012010-12-08 00:21:06 +02001032 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001033
1034 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001035 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001036
1037 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1038 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1039
1040 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001041
1042 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001043 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001044
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001046
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001047 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1048 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001049}
1050
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001051static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001052{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001053 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001054
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001055 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1056 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001057}
1058
Marcel Holtmann1904a852015-01-11 13:50:44 -08001059static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001060{
1061 BT_DBG("%s status 0x%02x", hdev->name, status);
1062
Johan Hedberga3172b72014-02-28 09:33:44 +02001063 if (hci_conn_count(hdev) == 0) {
1064 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001065 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001066 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001067}
1068
Johan Hedbergf2252572015-11-18 12:49:20 +02001069void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001070{
1071 struct mgmt_ev_advertising_added ev;
1072
1073 ev.instance = instance;
1074
1075 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1076}
1077
Johan Hedbergf2252572015-11-18 12:49:20 +02001078void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1079 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001080{
1081 struct mgmt_ev_advertising_removed ev;
1082
1083 ev.instance = instance;
1084
1085 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1086}
1087
Florian Grandel7816b822015-06-18 03:16:45 +02001088static void cancel_adv_timeout(struct hci_dev *hdev)
1089{
1090 if (hdev->adv_instance_timeout) {
1091 hdev->adv_instance_timeout = 0;
1092 cancel_delayed_work(&hdev->adv_instance_expire);
1093 }
1094}
1095
Johan Hedberg8b064a32014-02-24 14:52:22 +02001096static int clean_up_hci_state(struct hci_dev *hdev)
1097{
1098 struct hci_request req;
1099 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001100 bool discov_stopped;
1101 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001102
1103 hci_req_init(&req, hdev);
1104
1105 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1106 test_bit(HCI_PSCAN, &hdev->flags)) {
1107 u8 scan = 0x00;
1108 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1109 }
1110
Johan Hedbergf2252572015-11-18 12:49:20 +02001111 hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001112
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001113 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001114 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001115
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001116 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001117
1118 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001119 /* 0x15 == Terminated due to Power Off */
1120 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001121 }
1122
Johan Hedberg23a48092014-07-08 16:05:06 +03001123 err = hci_req_run(&req, clean_up_hci_complete);
1124 if (!err && discov_stopped)
1125 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1126
1127 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001128}
1129
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001130static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001131 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001132{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001133 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001134 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001135 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001137 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001138
Johan Hedberga7e80f22013-01-09 16:05:19 +02001139 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001140 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1141 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001143 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001144
Johan Hedberg333ae952015-03-17 13:48:47 +02001145 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001146 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1147 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001148 goto failed;
1149 }
1150
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001151 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001152 cancel_delayed_work(&hdev->power_off);
1153
1154 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001155 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1156 data, len);
1157 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001158 goto failed;
1159 }
1160 }
1161
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001162 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001163 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001164 goto failed;
1165 }
1166
Johan Hedberg03811012010-12-08 00:21:06 +02001167 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1168 if (!cmd) {
1169 err = -ENOMEM;
1170 goto failed;
1171 }
1172
Johan Hedberg8b064a32014-02-24 14:52:22 +02001173 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001174 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001175 err = 0;
1176 } else {
1177 /* Disconnect connections, stop scans, etc */
1178 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001179 if (!err)
1180 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1181 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001182
Johan Hedberg8b064a32014-02-24 14:52:22 +02001183 /* ENODATA means there were no HCI commands queued */
1184 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001185 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001186 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1187 err = 0;
1188 }
1189 }
Johan Hedberg03811012010-12-08 00:21:06 +02001190
Johan Hedberge41d8b42010-12-13 21:07:03 +02001191failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001192 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001193 return err;
1194}
1195
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001196static int new_settings(struct hci_dev *hdev, struct sock *skip)
1197{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001198 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001199
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001200 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1201 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001202}
1203
Johan Hedberg91a668b2014-07-09 13:28:26 +03001204int mgmt_new_settings(struct hci_dev *hdev)
1205{
1206 return new_settings(hdev, NULL);
1207}
1208
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001209struct cmd_lookup {
1210 struct sock *sk;
1211 struct hci_dev *hdev;
1212 u8 mgmt_status;
1213};
1214
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001215static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001216{
1217 struct cmd_lookup *match = data;
1218
1219 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1220
1221 list_del(&cmd->list);
1222
1223 if (match->sk == NULL) {
1224 match->sk = cmd->sk;
1225 sock_hold(match->sk);
1226 }
1227
1228 mgmt_pending_free(cmd);
1229}
1230
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001231static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001232{
1233 u8 *status = data;
1234
Johan Hedberga69e8372015-03-06 21:08:53 +02001235 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001236 mgmt_pending_remove(cmd);
1237}
1238
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001239static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001240{
1241 if (cmd->cmd_complete) {
1242 u8 *status = data;
1243
1244 cmd->cmd_complete(cmd, *status);
1245 mgmt_pending_remove(cmd);
1246
1247 return;
1248 }
1249
1250 cmd_status_rsp(cmd, data);
1251}
1252
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001253static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001254{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001255 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1256 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001257}
1258
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001259static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001260{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001261 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1262 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001263}
1264
Johan Hedberge6fe7982013-10-02 15:45:22 +03001265static u8 mgmt_bredr_support(struct hci_dev *hdev)
1266{
1267 if (!lmp_bredr_capable(hdev))
1268 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001269 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001270 return MGMT_STATUS_REJECTED;
1271 else
1272 return MGMT_STATUS_SUCCESS;
1273}
1274
1275static u8 mgmt_le_support(struct hci_dev *hdev)
1276{
1277 if (!lmp_le_capable(hdev))
1278 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001279 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001280 return MGMT_STATUS_REJECTED;
1281 else
1282 return MGMT_STATUS_SUCCESS;
1283}
1284
Johan Hedbergaed1a882015-11-22 17:24:44 +03001285void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001286{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001287 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001288
1289 BT_DBG("status 0x%02x", status);
1290
1291 hci_dev_lock(hdev);
1292
Johan Hedberg333ae952015-03-17 13:48:47 +02001293 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001294 if (!cmd)
1295 goto unlock;
1296
1297 if (status) {
1298 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001299 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001300 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001301 goto remove_cmd;
1302 }
1303
Johan Hedbergaed1a882015-11-22 17:24:44 +03001304 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1305 hdev->discov_timeout > 0) {
1306 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1307 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001308 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001309
1310 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001311 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001312
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001313remove_cmd:
1314 mgmt_pending_remove(cmd);
1315
1316unlock:
1317 hci_dev_unlock(hdev);
1318}
1319
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001320static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001321 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001322{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001323 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001324 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001325 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001326 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328 BT_DBG("request for %s", hdev->name);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001329
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001330 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1331 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001332 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1333 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001334
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001335 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001336 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1337 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001338
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001339 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001340
1341 /* Disabling discoverable requires that no timeout is set,
1342 * and enabling limited discoverable requires a timeout.
1343 */
1344 if ((cp->val == 0x00 && timeout > 0) ||
1345 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001346 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1347 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001348
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001349 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001350
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001351 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001352 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1353 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001354 goto failed;
1355 }
1356
Johan Hedberg333ae952015-03-17 13:48:47 +02001357 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1358 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001359 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1360 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001361 goto failed;
1362 }
1363
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001364 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001365 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1366 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001367 goto failed;
1368 }
1369
1370 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001371 bool changed = false;
1372
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001373 /* Setting limited discoverable when powered off is
1374 * not a valid operation since it requires a timeout
1375 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1376 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001377 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001378 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001379 changed = true;
1380 }
1381
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001382 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001383 if (err < 0)
1384 goto failed;
1385
1386 if (changed)
1387 err = new_settings(hdev, sk);
1388
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001389 goto failed;
1390 }
1391
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001392 /* If the current mode is the same, then just update the timeout
1393 * value with the new value. And if only the timeout gets updated,
1394 * then no need for any HCI transactions.
1395 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001396 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1397 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1398 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001399 cancel_delayed_work(&hdev->discov_off);
1400 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001401
Marcel Holtmann36261542013-10-15 08:28:51 -07001402 if (cp->val && hdev->discov_timeout > 0) {
1403 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001404 queue_delayed_work(hdev->req_workqueue,
1405 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001406 }
1407
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001408 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001409 goto failed;
1410 }
1411
1412 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1413 if (!cmd) {
1414 err = -ENOMEM;
1415 goto failed;
1416 }
1417
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001418 /* Cancel any potential discoverable timeout that might be
1419 * still active and store new timeout value. The arming of
1420 * the timeout happens in the complete handler.
1421 */
1422 cancel_delayed_work(&hdev->discov_off);
1423 hdev->discov_timeout = timeout;
1424
Johan Hedbergaed1a882015-11-22 17:24:44 +03001425 if (cp->val)
1426 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1427 else
1428 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1429
Johan Hedbergb456f872013-10-19 23:38:22 +03001430 /* Limited discoverable mode */
1431 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001432 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001433 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001434 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001435
Johan Hedbergaed1a882015-11-22 17:24:44 +03001436 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1437 err = 0;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001438
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001439failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001440 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001441 return err;
1442}
1443
Johan Hedberg406d7802013-03-15 17:07:09 -05001444static void write_fast_connectable(struct hci_request *req, bool enable)
1445{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001446 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001447 struct hci_cp_write_page_scan_activity acp;
1448 u8 type;
1449
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001450 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001451 return;
1452
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001453 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1454 return;
1455
Johan Hedberg406d7802013-03-15 17:07:09 -05001456 if (enable) {
1457 type = PAGE_SCAN_TYPE_INTERLACED;
1458
1459 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001460 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001461 } else {
1462 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1463
1464 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001465 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001466 }
1467
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001468 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001469
Johan Hedbergbd98b992013-03-15 17:07:13 -05001470 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1471 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1472 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1473 sizeof(acp), &acp);
1474
1475 if (hdev->page_scan_type != type)
1476 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001477}
1478
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001479void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001480{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001481 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001482
1483 BT_DBG("status 0x%02x", status);
1484
1485 hci_dev_lock(hdev);
1486
Johan Hedberg333ae952015-03-17 13:48:47 +02001487 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001488 if (!cmd)
1489 goto unlock;
1490
Johan Hedberg37438c12013-10-14 16:20:05 +03001491 if (status) {
1492 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001493 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001494 goto remove_cmd;
1495 }
1496
Johan Hedberg2b76f452013-03-15 17:07:04 -05001497 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001498 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001499
Johan Hedberg37438c12013-10-14 16:20:05 +03001500remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001501 mgmt_pending_remove(cmd);
1502
1503unlock:
1504 hci_dev_unlock(hdev);
1505}
1506
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001507static int set_connectable_update_settings(struct hci_dev *hdev,
1508 struct sock *sk, u8 val)
1509{
1510 bool changed = false;
1511 int err;
1512
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001513 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001514 changed = true;
1515
1516 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001517 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001518 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001519 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1520 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001521 }
1522
1523 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1524 if (err < 0)
1525 return err;
1526
Johan Hedberg562064e2014-07-08 16:35:34 +03001527 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001528 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001529 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001530 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001531 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001532
1533 return 0;
1534}
1535
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001536static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001537 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001538{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001539 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001540 struct mgmt_pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001541 int err;
1542
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001544
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001545 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1546 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001547 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1548 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001549
Johan Hedberga7e80f22013-01-09 16:05:19 +02001550 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001551 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1552 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001553
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001554 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001555
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001556 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001557 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001558 goto failed;
1559 }
1560
Johan Hedberg333ae952015-03-17 13:48:47 +02001561 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1562 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001563 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1564 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565 goto failed;
1566 }
1567
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1569 if (!cmd) {
1570 err = -ENOMEM;
1571 goto failed;
1572 }
1573
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001574 if (cp->val) {
1575 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1576 } else {
1577 if (hdev->discov_timeout > 0)
1578 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001579
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001580 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1581 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1582 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001583 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001584
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001585 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1586 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001587
1588failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001589 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001590 return err;
1591}
1592
Johan Hedbergb2939472014-07-30 09:22:23 +03001593static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001594 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001595{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001596 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001597 bool changed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001598 int err;
1599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001600 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001601
Johan Hedberga7e80f22013-01-09 16:05:19 +02001602 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001603 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1604 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001605
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001606 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001607
1608 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001609 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001610 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001611 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001612
Johan Hedbergb2939472014-07-30 09:22:23 +03001613 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001614 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001615 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001616
Marcel Holtmann55594352013-10-06 16:11:57 -07001617 if (changed)
1618 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001619
Marcel Holtmann55594352013-10-06 16:11:57 -07001620unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001621 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001622 return err;
1623}
1624
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001625static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1626 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001627{
1628 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001629 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001630 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001631 int err;
1632
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001633 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001634
Johan Hedberge6fe7982013-10-02 15:45:22 +03001635 status = mgmt_bredr_support(hdev);
1636 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001637 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1638 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001639
Johan Hedberga7e80f22013-01-09 16:05:19 +02001640 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001641 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1642 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001643
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001644 hci_dev_lock(hdev);
1645
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001646 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001647 bool changed = false;
1648
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001649 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001650 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001651 changed = true;
1652 }
1653
1654 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1655 if (err < 0)
1656 goto failed;
1657
1658 if (changed)
1659 err = new_settings(hdev, sk);
1660
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001661 goto failed;
1662 }
1663
Johan Hedberg333ae952015-03-17 13:48:47 +02001664 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001665 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1666 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001667 goto failed;
1668 }
1669
1670 val = !!cp->val;
1671
1672 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1673 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1674 goto failed;
1675 }
1676
1677 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1678 if (!cmd) {
1679 err = -ENOMEM;
1680 goto failed;
1681 }
1682
1683 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1684 if (err < 0) {
1685 mgmt_pending_remove(cmd);
1686 goto failed;
1687 }
1688
1689failed:
1690 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001691 return err;
1692}
1693
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001694static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001695{
1696 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001697 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001698 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001699 int err;
1700
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001701 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001702
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001703 status = mgmt_bredr_support(hdev);
1704 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001705 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001706
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001707 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001708 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1709 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001710
Johan Hedberga7e80f22013-01-09 16:05:19 +02001711 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001712 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1713 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001714
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001715 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001716
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001717 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001718 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001719
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001720 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001721 changed = !hci_dev_test_and_set_flag(hdev,
1722 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001723 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001724 changed = hci_dev_test_and_clear_flag(hdev,
1725 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001726 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001727 changed = hci_dev_test_and_clear_flag(hdev,
1728 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001729 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001730 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001731 }
1732
1733 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1734 if (err < 0)
1735 goto failed;
1736
1737 if (changed)
1738 err = new_settings(hdev, sk);
1739
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001740 goto failed;
1741 }
1742
Johan Hedberg333ae952015-03-17 13:48:47 +02001743 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001744 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1745 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001746 goto failed;
1747 }
1748
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001749 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001750 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1751 goto failed;
1752 }
1753
1754 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1755 if (!cmd) {
1756 err = -ENOMEM;
1757 goto failed;
1758 }
1759
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001760 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001761 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1762 sizeof(cp->val), &cp->val);
1763
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001764 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001765 if (err < 0) {
1766 mgmt_pending_remove(cmd);
1767 goto failed;
1768 }
1769
1770failed:
1771 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001772 return err;
1773}
1774
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001775static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001776{
1777 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001778 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001779 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001780 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001781
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001782 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001783
Johan Hedberge6fe7982013-10-02 15:45:22 +03001784 status = mgmt_bredr_support(hdev);
1785 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001786 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001787
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001788 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001789 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1790 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001791
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001792 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001793 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1794 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001795
Johan Hedberga7e80f22013-01-09 16:05:19 +02001796 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001797 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1798 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001799
Marcel Holtmannee392692013-10-01 22:59:23 -07001800 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001801
Johan Hedberg333ae952015-03-17 13:48:47 +02001802 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001803 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1804 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001805 goto unlock;
1806 }
1807
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001808 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001809 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001810 } else {
1811 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001812 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1813 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001814 goto unlock;
1815 }
1816
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001817 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001818 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001819
1820 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1821 if (err < 0)
1822 goto unlock;
1823
1824 if (changed)
1825 err = new_settings(hdev, sk);
1826
1827unlock:
1828 hci_dev_unlock(hdev);
1829 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001830}
1831
Marcel Holtmann1904a852015-01-11 13:50:44 -08001832static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001833{
1834 struct cmd_lookup match = { NULL, hdev };
1835
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301836 hci_dev_lock(hdev);
1837
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001838 if (status) {
1839 u8 mgmt_err = mgmt_status(status);
1840
1841 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1842 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301843 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001844 }
1845
1846 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1847
1848 new_settings(hdev, match.sk);
1849
1850 if (match.sk)
1851 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001852
1853 /* Make sure the controller has a good default for
1854 * advertising data. Restrict the update to when LE
1855 * has actually been enabled. During power on, the
1856 * update in powered_update_hci will take care of it.
1857 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001858 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001859 struct hci_request req;
1860
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001861 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001862 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
1863 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001864 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001865 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001866 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301867
1868unlock:
1869 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001870}
1871
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001872static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001873{
1874 struct mgmt_mode *cp = data;
1875 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001876 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001877 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001878 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001879 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001880
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001882
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001883 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001884 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1885 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001886
Johan Hedberga7e80f22013-01-09 16:05:19 +02001887 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001888 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1889 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001890
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001891 /* Bluetooth single mode LE only controllers or dual-mode
1892 * controllers configured as LE only devices, do not allow
1893 * switching LE off. These have either LE enabled explicitly
1894 * or BR/EDR has been previously switched off.
1895 *
1896 * When trying to enable an already enabled LE, then gracefully
1897 * send a positive response. Trying to disable it however will
1898 * result into rejection.
1899 */
1900 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1901 if (cp->val == 0x01)
1902 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1903
Johan Hedberga69e8372015-03-06 21:08:53 +02001904 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1905 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001906 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001907
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001908 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001909
1910 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001911 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001912
Florian Grandel847818d2015-06-18 03:16:46 +02001913 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02001914 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001915
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001916 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001917 bool changed = false;
1918
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001919 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001920 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001921 changed = true;
1922 }
1923
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001924 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001925 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001926 changed = true;
1927 }
1928
Johan Hedberg06199cf2012-02-22 16:37:11 +02001929 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1930 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001931 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001932
1933 if (changed)
1934 err = new_settings(hdev, sk);
1935
Johan Hedberg1de028c2012-02-29 19:55:35 -08001936 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001937 }
1938
Johan Hedberg333ae952015-03-17 13:48:47 +02001939 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1940 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001941 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1942 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001943 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001944 }
1945
1946 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1947 if (!cmd) {
1948 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001949 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001950 }
1951
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001952 hci_req_init(&req, hdev);
1953
Johan Hedberg06199cf2012-02-22 16:37:11 +02001954 memset(&hci_cp, 0, sizeof(hci_cp));
1955
1956 if (val) {
1957 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001958 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001959 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001960 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001961 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 }
1963
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001964 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1965 &hci_cp);
1966
1967 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301968 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001969 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001970
Johan Hedberg1de028c2012-02-29 19:55:35 -08001971unlock:
1972 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001973 return err;
1974}
1975
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001976/* This is a helper function to test for pending mgmt commands that can
1977 * cause CoD or EIR HCI commands. We can only allow one such pending
1978 * mgmt command at a time since otherwise we cannot easily track what
1979 * the current values are, will be, and based on that calculate if a new
1980 * HCI command needs to be sent and if yes with what value.
1981 */
1982static bool pending_eir_or_class(struct hci_dev *hdev)
1983{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001984 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001985
1986 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1987 switch (cmd->opcode) {
1988 case MGMT_OP_ADD_UUID:
1989 case MGMT_OP_REMOVE_UUID:
1990 case MGMT_OP_SET_DEV_CLASS:
1991 case MGMT_OP_SET_POWERED:
1992 return true;
1993 }
1994 }
1995
1996 return false;
1997}
1998
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001999static const u8 bluetooth_base_uuid[] = {
2000 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2001 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2002};
2003
2004static u8 get_uuid_size(const u8 *uuid)
2005{
2006 u32 val;
2007
2008 if (memcmp(uuid, bluetooth_base_uuid, 12))
2009 return 128;
2010
2011 val = get_unaligned_le32(&uuid[12]);
2012 if (val > 0xffff)
2013 return 32;
2014
2015 return 16;
2016}
2017
Johan Hedberg92da6092013-03-15 17:06:55 -05002018static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2019{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002020 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002021
2022 hci_dev_lock(hdev);
2023
Johan Hedberg333ae952015-03-17 13:48:47 +02002024 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002025 if (!cmd)
2026 goto unlock;
2027
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002028 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2029 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002030
2031 mgmt_pending_remove(cmd);
2032
2033unlock:
2034 hci_dev_unlock(hdev);
2035}
2036
Marcel Holtmann1904a852015-01-11 13:50:44 -08002037static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002038{
2039 BT_DBG("status 0x%02x", status);
2040
2041 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2042}
2043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002045{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002046 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002047 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002048 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002049 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002050 int err;
2051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002052 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002053
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002054 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002056 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002057 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2058 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002059 goto failed;
2060 }
2061
Andre Guedes92c4c202012-06-07 19:05:44 -03002062 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063 if (!uuid) {
2064 err = -ENOMEM;
2065 goto failed;
2066 }
2067
2068 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002069 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002070 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002071
Johan Hedbergde66aa62013-01-27 00:31:27 +02002072 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002073
Johan Hedberg890ea892013-03-15 17:06:52 -05002074 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002075
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002076 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002077 update_eir(&req);
2078
Johan Hedberg92da6092013-03-15 17:06:55 -05002079 err = hci_req_run(&req, add_uuid_complete);
2080 if (err < 0) {
2081 if (err != -ENODATA)
2082 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002083
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002084 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2085 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002086 goto failed;
2087 }
2088
2089 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002090 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002091 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002092 goto failed;
2093 }
2094
2095 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002096
2097failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002098 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099 return err;
2100}
2101
Johan Hedberg24b78d02012-02-23 23:24:30 +02002102static bool enable_service_cache(struct hci_dev *hdev)
2103{
2104 if (!hdev_is_powered(hdev))
2105 return false;
2106
Marcel Holtmann238be782015-03-13 02:11:06 -07002107 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002108 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2109 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002110 return true;
2111 }
2112
2113 return false;
2114}
2115
Marcel Holtmann1904a852015-01-11 13:50:44 -08002116static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002117{
2118 BT_DBG("status 0x%02x", status);
2119
2120 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2121}
2122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002123static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002124 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002126 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002127 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002128 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129 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 -05002130 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002131 int err, found;
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002136
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002137 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002138 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2139 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002140 goto unlock;
2141 }
2142
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002143 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002144 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002145
Johan Hedberg24b78d02012-02-23 23:24:30 +02002146 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002147 err = mgmt_cmd_complete(sk, hdev->id,
2148 MGMT_OP_REMOVE_UUID,
2149 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002150 goto unlock;
2151 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002152
Johan Hedberg9246a862012-02-23 21:33:16 +02002153 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002154 }
2155
2156 found = 0;
2157
Johan Hedberg056341c2013-01-27 00:31:30 +02002158 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002159 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2160 continue;
2161
2162 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002163 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164 found++;
2165 }
2166
2167 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002168 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2169 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002170 goto unlock;
2171 }
2172
Johan Hedberg9246a862012-02-23 21:33:16 +02002173update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002174 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002175
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002176 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002177 update_eir(&req);
2178
Johan Hedberg92da6092013-03-15 17:06:55 -05002179 err = hci_req_run(&req, remove_uuid_complete);
2180 if (err < 0) {
2181 if (err != -ENODATA)
2182 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002183
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002184 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2185 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002186 goto unlock;
2187 }
2188
2189 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002190 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002191 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002192 goto unlock;
2193 }
2194
2195 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002196
2197unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002198 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002199 return err;
2200}
2201
Marcel Holtmann1904a852015-01-11 13:50:44 -08002202static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002203{
2204 BT_DBG("status 0x%02x", status);
2205
2206 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2207}
2208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002213 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002214 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002215 int err;
2216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002217 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002218
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002219 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002220 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2221 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002222
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002223 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002224
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002225 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002226 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2227 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002228 goto unlock;
2229 }
2230
2231 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002234 goto unlock;
2235 }
2236
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002237 hdev->major_class = cp->major;
2238 hdev->minor_class = cp->minor;
2239
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002240 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002241 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2242 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002243 goto unlock;
2244 }
2245
Johan Hedberg890ea892013-03-15 17:06:52 -05002246 hci_req_init(&req, hdev);
2247
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002248 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002249 hci_dev_unlock(hdev);
2250 cancel_delayed_work_sync(&hdev->service_cache);
2251 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002252 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002253 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002254
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002255 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002256
Johan Hedberg92da6092013-03-15 17:06:55 -05002257 err = hci_req_run(&req, set_class_complete);
2258 if (err < 0) {
2259 if (err != -ENODATA)
2260 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002261
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002262 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2263 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002264 goto unlock;
2265 }
2266
2267 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002268 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002269 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002270 goto unlock;
2271 }
2272
2273 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002274
Johan Hedbergb5235a62012-02-21 14:32:24 +02002275unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002276 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002277 return err;
2278}
2279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002281 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002282{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002284 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2285 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002286 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002287 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002288 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002289
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002290 BT_DBG("request for %s", hdev->name);
2291
2292 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2294 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002295
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002296 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002297 if (key_count > max_key_count) {
2298 BT_ERR("load_link_keys: too big key_count value %u",
2299 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002300 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2301 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002302 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002303
Johan Hedberg86742e12011-11-07 23:13:38 +02002304 expected_len = sizeof(*cp) + key_count *
2305 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002306 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002307 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002308 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002309 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2310 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002311 }
2312
Johan Hedberg4ae14302013-01-20 14:27:13 +02002313 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2315 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002316
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002317 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002318 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002319
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002320 for (i = 0; i < key_count; i++) {
2321 struct mgmt_link_key_info *key = &cp->keys[i];
2322
Marcel Holtmann8e991132014-01-10 02:07:25 -08002323 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002324 return mgmt_cmd_status(sk, hdev->id,
2325 MGMT_OP_LOAD_LINK_KEYS,
2326 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002327 }
2328
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002329 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002330
2331 hci_link_keys_clear(hdev);
2332
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002334 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002335 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002336 changed = hci_dev_test_and_clear_flag(hdev,
2337 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002338
2339 if (changed)
2340 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002342 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002343 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344
Johan Hedberg58e92932014-06-24 14:00:26 +03002345 /* Always ignore debug keys and require a new pairing if
2346 * the user wants to use them.
2347 */
2348 if (key->type == HCI_LK_DEBUG_COMBINATION)
2349 continue;
2350
Johan Hedberg7652ff62014-06-24 13:15:49 +03002351 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2352 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353 }
2354
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002355 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002357 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002359 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360}
2361
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002362static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002364{
2365 struct mgmt_ev_device_unpaired ev;
2366
2367 bacpy(&ev.addr.bdaddr, bdaddr);
2368 ev.addr.type = addr_type;
2369
2370 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002372}
2373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002377 struct mgmt_cp_unpair_device *cp = data;
2378 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002379 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002380 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002381 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002382 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002383 int err;
2384
Johan Hedberga8a1d192011-11-10 15:54:38 +02002385 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002386 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2387 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002388
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002389 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002390 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2391 MGMT_STATUS_INVALID_PARAMS,
2392 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002393
Johan Hedberg118da702013-01-20 14:27:20 +02002394 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002395 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2396 MGMT_STATUS_INVALID_PARAMS,
2397 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002398
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399 hci_dev_lock(hdev);
2400
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002401 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002402 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2403 MGMT_STATUS_NOT_POWERED, &rp,
2404 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002405 goto unlock;
2406 }
2407
Johan Hedberge0b2b272014-02-18 17:14:31 +02002408 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002409 /* If disconnection is requested, then look up the
2410 * connection. If the remote device is connected, it
2411 * will be later used to terminate the link.
2412 *
2413 * Setting it to NULL explicitly will cause no
2414 * termination of the link.
2415 */
2416 if (cp->disconnect)
2417 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2418 &cp->addr.bdaddr);
2419 else
2420 conn = NULL;
2421
Johan Hedberg124f6e32012-02-09 13:50:12 +02002422 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002423 if (err < 0) {
2424 err = mgmt_cmd_complete(sk, hdev->id,
2425 MGMT_OP_UNPAIR_DEVICE,
2426 MGMT_STATUS_NOT_PAIRED, &rp,
2427 sizeof(rp));
2428 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002429 }
2430
Johan Hedbergec182f02015-10-21 18:03:03 +03002431 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002432 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002433
Johan Hedbergec182f02015-10-21 18:03:03 +03002434 /* LE address type */
2435 addr_type = le_addr_type(cp->addr.type);
2436
2437 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2438
2439 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002440 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002441 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2442 MGMT_STATUS_NOT_PAIRED, &rp,
2443 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002444 goto unlock;
2445 }
2446
Johan Hedbergec182f02015-10-21 18:03:03 +03002447 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2448 if (!conn) {
2449 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2450 goto done;
2451 }
2452
Johan Hedbergc81d5552015-10-22 09:38:35 +03002453 /* Abort any ongoing SMP pairing */
2454 smp_cancel_pairing(conn);
2455
Johan Hedbergec182f02015-10-21 18:03:03 +03002456 /* Defer clearing up the connection parameters until closing to
2457 * give a chance of keeping them if a repairing happens.
2458 */
2459 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2460
Johan Hedbergfc643612015-10-22 09:38:31 +03002461 /* Disable auto-connection parameters if present */
2462 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2463 if (params) {
2464 if (params->explicit_connect)
2465 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2466 else
2467 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2468 }
2469
Johan Hedbergec182f02015-10-21 18:03:03 +03002470 /* If disconnection is not requested, then clear the connection
2471 * variable so that the link is not terminated.
2472 */
2473 if (!cp->disconnect)
2474 conn = NULL;
2475
2476done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002477 /* If the connection variable is set, then termination of the
2478 * link is requested.
2479 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002480 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002481 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2482 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002483 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002484 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002485 }
2486
Johan Hedberg124f6e32012-02-09 13:50:12 +02002487 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002488 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002489 if (!cmd) {
2490 err = -ENOMEM;
2491 goto unlock;
2492 }
2493
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002494 cmd->cmd_complete = addr_cmd_complete;
2495
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002496 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002497 if (err < 0)
2498 mgmt_pending_remove(cmd);
2499
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002500unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002502 return err;
2503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002508 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002509 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002510 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002511 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002512 int err;
2513
2514 BT_DBG("");
2515
Johan Hedberg06a63b12013-01-20 14:27:21 +02002516 memset(&rp, 0, sizeof(rp));
2517 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2518 rp.addr.type = cp->addr.type;
2519
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002520 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002521 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2522 MGMT_STATUS_INVALID_PARAMS,
2523 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002526
2527 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002528 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2529 MGMT_STATUS_NOT_POWERED, &rp,
2530 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002531 goto failed;
2532 }
2533
Johan Hedberg333ae952015-03-17 13:48:47 +02002534 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002535 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2536 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002537 goto failed;
2538 }
2539
Andre Guedes591f47f2012-04-24 21:02:49 -03002540 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002541 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2542 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002543 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002544 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2545 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002546
Vishal Agarwalf9607272012-06-13 05:32:43 +05302547 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002548 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2549 MGMT_STATUS_NOT_CONNECTED, &rp,
2550 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002551 goto failed;
2552 }
2553
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002554 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002555 if (!cmd) {
2556 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002557 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002558 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002559
Johan Hedbergf5818c22014-12-05 13:36:02 +02002560 cmd->cmd_complete = generic_cmd_complete;
2561
Johan Hedberge3f2f922014-08-18 20:33:33 +03002562 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002563 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002564 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565
2566failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002567 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002568 return err;
2569}
2570
Andre Guedes57c14772012-04-24 21:02:50 -03002571static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002572{
2573 switch (link_type) {
2574 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002575 switch (addr_type) {
2576 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002577 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002578
Johan Hedberg48264f02011-11-09 13:58:58 +02002579 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002580 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002581 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002582 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002583
Johan Hedberg4c659c32011-11-07 23:13:39 +02002584 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002585 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002586 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002587 }
2588}
2589
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2591 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002592{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002593 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002594 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002595 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002596 int err;
2597 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002598
2599 BT_DBG("");
2600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002602
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002603 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002604 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2605 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002606 goto unlock;
2607 }
2608
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002609 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002610 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2611 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002612 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002613 }
2614
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002615 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002616 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002617 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002618 err = -ENOMEM;
2619 goto unlock;
2620 }
2621
Johan Hedberg2784eb42011-01-21 13:56:35 +02002622 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002623 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002624 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2625 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002626 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002627 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002628 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002629 continue;
2630 i++;
2631 }
2632
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002633 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002634
Johan Hedberg4c659c32011-11-07 23:13:39 +02002635 /* Recalculate length in case of filtered SCO connections, etc */
2636 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002637
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002638 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2639 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002640
Johan Hedberga38528f2011-01-22 06:46:43 +02002641 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002642
2643unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002644 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002645 return err;
2646}
2647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002650{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002651 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002652 int err;
2653
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002654 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002655 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002656 if (!cmd)
2657 return -ENOMEM;
2658
Johan Hedbergd8457692012-02-17 14:24:57 +02002659 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002660 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002661 if (err < 0)
2662 mgmt_pending_remove(cmd);
2663
2664 return err;
2665}
2666
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002667static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002668 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002669{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002670 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002671 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002672 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002673 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002674 int err;
2675
2676 BT_DBG("");
2677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002678 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002679
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002680 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002681 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2682 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002683 goto failed;
2684 }
2685
Johan Hedbergd8457692012-02-17 14:24:57 +02002686 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002687 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002688 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2689 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002690 goto failed;
2691 }
2692
2693 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002694 struct mgmt_cp_pin_code_neg_reply ncp;
2695
2696 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002697
2698 BT_ERR("PIN code is not 16 bytes long");
2699
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002700 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002701 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002702 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2703 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002704
2705 goto failed;
2706 }
2707
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002708 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002709 if (!cmd) {
2710 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002712 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002713
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002714 cmd->cmd_complete = addr_cmd_complete;
2715
Johan Hedbergd8457692012-02-17 14:24:57 +02002716 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002718 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002719
2720 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2721 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002722 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002723
2724failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002725 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002726 return err;
2727}
2728
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2730 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002731{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002732 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002733
2734 BT_DBG("");
2735
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002736 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002737 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2738 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002739
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002740 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002741
2742 hdev->io_capability = cp->io_capability;
2743
2744 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002745 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002746
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002747 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002748
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002749 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2750 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002751}
2752
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002753static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002754{
2755 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002756 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002757
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002758 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002759 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2760 continue;
2761
Johan Hedberge9a416b2011-02-19 12:05:56 -03002762 if (cmd->user_data != conn)
2763 continue;
2764
2765 return cmd;
2766 }
2767
2768 return NULL;
2769}
2770
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002771static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002772{
2773 struct mgmt_rp_pair_device rp;
2774 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002775 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002776
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002777 bacpy(&rp.addr.bdaddr, &conn->dst);
2778 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002779
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002780 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2781 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002782
2783 /* So we don't get further callbacks for this connection */
2784 conn->connect_cfm_cb = NULL;
2785 conn->security_cfm_cb = NULL;
2786 conn->disconn_cfm_cb = NULL;
2787
David Herrmann76a68ba2013-04-06 20:28:37 +02002788 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002789
2790 /* The device is paired so there is no need to remove
2791 * its connection parameters anymore.
2792 */
2793 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002794
2795 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002796
2797 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002798}
2799
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002800void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2801{
2802 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002803 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002804
2805 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002806 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002807 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002808 mgmt_pending_remove(cmd);
2809 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002810}
2811
Johan Hedberge9a416b2011-02-19 12:05:56 -03002812static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2813{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002814 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002815
2816 BT_DBG("status %u", status);
2817
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002818 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002819 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002820 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002821 return;
2822 }
2823
2824 cmd->cmd_complete(cmd, mgmt_status(status));
2825 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002826}
2827
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002828static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302829{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002830 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302831
2832 BT_DBG("status %u", status);
2833
2834 if (!status)
2835 return;
2836
2837 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002838 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302839 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002840 return;
2841 }
2842
2843 cmd->cmd_complete(cmd, mgmt_status(status));
2844 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302845}
2846
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002847static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002848 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002849{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002850 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002851 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002852 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002853 u8 sec_level, auth_type;
2854 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002855 int err;
2856
2857 BT_DBG("");
2858
Szymon Jancf950a30e2013-01-18 12:48:07 +01002859 memset(&rp, 0, sizeof(rp));
2860 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2861 rp.addr.type = cp->addr.type;
2862
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002863 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002864 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2865 MGMT_STATUS_INVALID_PARAMS,
2866 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002867
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002868 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002869 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2870 MGMT_STATUS_INVALID_PARAMS,
2871 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002873 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002874
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002875 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002876 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2877 MGMT_STATUS_NOT_POWERED, &rp,
2878 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002879 goto unlock;
2880 }
2881
Johan Hedberg55e76b32015-03-10 22:34:40 +02002882 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2883 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2884 MGMT_STATUS_ALREADY_PAIRED, &rp,
2885 sizeof(rp));
2886 goto unlock;
2887 }
2888
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002889 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002890 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002891
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002892 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002893 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2894 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002895 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002896 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002897 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002898
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002899 /* When pairing a new device, it is expected to remember
2900 * this device for future connections. Adding the connection
2901 * parameter information ahead of time allows tracking
2902 * of the slave preferred values and will speed up any
2903 * further connection establishment.
2904 *
2905 * If connection parameters already exist, then they
2906 * will be kept and this function does nothing.
2907 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002908 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2909
2910 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2911 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002912
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002913 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2914 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002915 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002916 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002917
Ville Tervo30e76272011-02-22 16:10:53 -03002918 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002919 int status;
2920
2921 if (PTR_ERR(conn) == -EBUSY)
2922 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002923 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2924 status = MGMT_STATUS_NOT_SUPPORTED;
2925 else if (PTR_ERR(conn) == -ECONNREFUSED)
2926 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002927 else
2928 status = MGMT_STATUS_CONNECT_FAILED;
2929
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002930 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2931 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002932 goto unlock;
2933 }
2934
2935 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002936 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002937 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2938 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002939 goto unlock;
2940 }
2941
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002942 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002943 if (!cmd) {
2944 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002945 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002946 goto unlock;
2947 }
2948
Johan Hedberg04ab2742014-12-05 13:36:04 +02002949 cmd->cmd_complete = pairing_complete;
2950
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002951 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002952 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002953 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002954 conn->security_cfm_cb = pairing_complete_cb;
2955 conn->disconn_cfm_cb = pairing_complete_cb;
2956 } else {
2957 conn->connect_cfm_cb = le_pairing_complete_cb;
2958 conn->security_cfm_cb = le_pairing_complete_cb;
2959 conn->disconn_cfm_cb = le_pairing_complete_cb;
2960 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002961
Johan Hedberge9a416b2011-02-19 12:05:56 -03002962 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002963 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002964
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002965 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002966 hci_conn_security(conn, sec_level, auth_type, true)) {
2967 cmd->cmd_complete(cmd, 0);
2968 mgmt_pending_remove(cmd);
2969 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002970
2971 err = 0;
2972
2973unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002974 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002975 return err;
2976}
2977
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002978static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2979 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002980{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002981 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002982 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002983 struct hci_conn *conn;
2984 int err;
2985
2986 BT_DBG("");
2987
Johan Hedberg28424702012-02-02 04:02:29 +02002988 hci_dev_lock(hdev);
2989
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002990 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002991 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2992 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002993 goto unlock;
2994 }
2995
Johan Hedberg333ae952015-03-17 13:48:47 +02002996 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002997 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002998 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2999 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003000 goto unlock;
3001 }
3002
3003 conn = cmd->user_data;
3004
3005 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003006 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3007 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003008 goto unlock;
3009 }
3010
Johan Hedberga511b352014-12-11 21:45:45 +02003011 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3012 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003013
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003014 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3015 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003016unlock:
3017 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003018 return err;
3019}
3020
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003021static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003022 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003024{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003025 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003026 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003027 int err;
3028
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003029 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003030
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003031 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003032 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3033 MGMT_STATUS_NOT_POWERED, addr,
3034 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003035 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003036 }
3037
Johan Hedberg1707c602013-03-15 17:07:15 -05003038 if (addr->type == BDADDR_BREDR)
3039 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003040 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003041 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3042 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003043
Johan Hedberg272d90d2012-02-09 15:26:12 +02003044 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003045 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3046 MGMT_STATUS_NOT_CONNECTED, addr,
3047 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003048 goto done;
3049 }
3050
Johan Hedberg1707c602013-03-15 17:07:15 -05003051 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003052 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003053 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003054 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3055 MGMT_STATUS_SUCCESS, addr,
3056 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003057 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003058 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3059 MGMT_STATUS_FAILED, addr,
3060 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003061
Brian Gix47c15e22011-11-16 13:53:14 -08003062 goto done;
3063 }
3064
Johan Hedberg1707c602013-03-15 17:07:15 -05003065 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003066 if (!cmd) {
3067 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003068 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003069 }
3070
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003071 cmd->cmd_complete = addr_cmd_complete;
3072
Brian Gix0df4c182011-11-16 13:53:13 -08003073 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003074 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3075 struct hci_cp_user_passkey_reply cp;
3076
Johan Hedberg1707c602013-03-15 17:07:15 -05003077 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003078 cp.passkey = passkey;
3079 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3080 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003081 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3082 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003083
Johan Hedberga664b5b2011-02-19 12:06:02 -03003084 if (err < 0)
3085 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003086
Brian Gix0df4c182011-11-16 13:53:13 -08003087done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003088 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003089 return err;
3090}
3091
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303092static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3093 void *data, u16 len)
3094{
3095 struct mgmt_cp_pin_code_neg_reply *cp = data;
3096
3097 BT_DBG("");
3098
Johan Hedberg1707c602013-03-15 17:07:15 -05003099 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303100 MGMT_OP_PIN_CODE_NEG_REPLY,
3101 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3102}
3103
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003104static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3105 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003106{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003107 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003108
3109 BT_DBG("");
3110
3111 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003112 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3113 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003114
Johan Hedberg1707c602013-03-15 17:07:15 -05003115 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003116 MGMT_OP_USER_CONFIRM_REPLY,
3117 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003118}
3119
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003120static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003121 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003122{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003123 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003124
3125 BT_DBG("");
3126
Johan Hedberg1707c602013-03-15 17:07:15 -05003127 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003128 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3129 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003130}
3131
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3133 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003134{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003135 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003136
3137 BT_DBG("");
3138
Johan Hedberg1707c602013-03-15 17:07:15 -05003139 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003140 MGMT_OP_USER_PASSKEY_REPLY,
3141 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003142}
3143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003147 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003148
3149 BT_DBG("");
3150
Johan Hedberg1707c602013-03-15 17:07:15 -05003151 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3153 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003154}
3155
Johan Hedberg13928972013-03-15 17:07:00 -05003156static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003157{
Johan Hedberg13928972013-03-15 17:07:00 -05003158 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003159 struct hci_cp_write_local_name cp;
3160
Johan Hedberg13928972013-03-15 17:07:00 -05003161 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003162
Johan Hedberg890ea892013-03-15 17:06:52 -05003163 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003164}
3165
Marcel Holtmann1904a852015-01-11 13:50:44 -08003166static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003167{
3168 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003169 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003170
3171 BT_DBG("status 0x%02x", status);
3172
3173 hci_dev_lock(hdev);
3174
Johan Hedberg333ae952015-03-17 13:48:47 +02003175 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003176 if (!cmd)
3177 goto unlock;
3178
3179 cp = cmd->param;
3180
3181 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003182 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3183 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003184 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003185 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3186 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003187
3188 mgmt_pending_remove(cmd);
3189
3190unlock:
3191 hci_dev_unlock(hdev);
3192}
3193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003194static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003195 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003196{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003197 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003198 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003199 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003200 int err;
3201
3202 BT_DBG("");
3203
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003204 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003205
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003206 /* If the old values are the same as the new ones just return a
3207 * direct command complete event.
3208 */
3209 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3210 !memcmp(hdev->short_name, cp->short_name,
3211 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003212 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3213 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003214 goto failed;
3215 }
3216
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003217 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003218
Johan Hedbergb5235a62012-02-21 14:32:24 +02003219 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003220 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003221
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003222 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3223 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003224 if (err < 0)
3225 goto failed;
3226
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003227 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3228 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003229
Johan Hedbergb5235a62012-02-21 14:32:24 +02003230 goto failed;
3231 }
3232
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003233 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003234 if (!cmd) {
3235 err = -ENOMEM;
3236 goto failed;
3237 }
3238
Johan Hedberg13928972013-03-15 17:07:00 -05003239 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3240
Johan Hedberg890ea892013-03-15 17:06:52 -05003241 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003242
3243 if (lmp_bredr_capable(hdev)) {
3244 update_name(&req);
3245 update_eir(&req);
3246 }
3247
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003248 /* The name is stored in the scan response data and so
3249 * no need to udpate the advertising data here.
3250 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003251 if (lmp_le_capable(hdev))
Johan Hedbergf2252572015-11-18 12:49:20 +02003252 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Johan Hedberg3f985052013-03-15 17:07:02 -05003253
Johan Hedberg13928972013-03-15 17:07:00 -05003254 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003255 if (err < 0)
3256 mgmt_pending_remove(cmd);
3257
3258failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003259 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003260 return err;
3261}
3262
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003263static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3264 u16 opcode, struct sk_buff *skb)
3265{
3266 struct mgmt_rp_read_local_oob_data mgmt_rp;
3267 size_t rp_size = sizeof(mgmt_rp);
3268 struct mgmt_pending_cmd *cmd;
3269
3270 BT_DBG("%s status %u", hdev->name, status);
3271
3272 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3273 if (!cmd)
3274 return;
3275
3276 if (status || !skb) {
3277 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3278 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3279 goto remove;
3280 }
3281
3282 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3283
3284 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3285 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3286
3287 if (skb->len < sizeof(*rp)) {
3288 mgmt_cmd_status(cmd->sk, hdev->id,
3289 MGMT_OP_READ_LOCAL_OOB_DATA,
3290 MGMT_STATUS_FAILED);
3291 goto remove;
3292 }
3293
3294 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3295 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3296
3297 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3298 } else {
3299 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3300
3301 if (skb->len < sizeof(*rp)) {
3302 mgmt_cmd_status(cmd->sk, hdev->id,
3303 MGMT_OP_READ_LOCAL_OOB_DATA,
3304 MGMT_STATUS_FAILED);
3305 goto remove;
3306 }
3307
3308 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3309 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3310
3311 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3312 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3313 }
3314
3315 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3316 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3317
3318remove:
3319 mgmt_pending_remove(cmd);
3320}
3321
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003322static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003323 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003324{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003325 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003326 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003327 int err;
3328
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003329 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003330
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003331 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003332
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003333 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003334 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3335 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003336 goto unlock;
3337 }
3338
Andre Guedes9a1a1992012-07-24 15:03:48 -03003339 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003340 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3341 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003342 goto unlock;
3343 }
3344
Johan Hedberg333ae952015-03-17 13:48:47 +02003345 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003346 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3347 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003348 goto unlock;
3349 }
3350
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003351 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003352 if (!cmd) {
3353 err = -ENOMEM;
3354 goto unlock;
3355 }
3356
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003357 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003358
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003359 if (bredr_sc_enabled(hdev))
3360 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3361 else
3362 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3363
3364 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003365 if (err < 0)
3366 mgmt_pending_remove(cmd);
3367
3368unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003369 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003370 return err;
3371}
3372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003373static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003374 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003375{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003376 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003377 int err;
3378
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003379 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003380
Johan Hedberg5d57e792015-01-23 10:10:38 +02003381 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003382 return mgmt_cmd_complete(sk, hdev->id,
3383 MGMT_OP_ADD_REMOTE_OOB_DATA,
3384 MGMT_STATUS_INVALID_PARAMS,
3385 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003386
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003387 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003388
Marcel Holtmannec109112014-01-10 02:07:30 -08003389 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3390 struct mgmt_cp_add_remote_oob_data *cp = data;
3391 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003392
Johan Hedbergc19a4952014-11-17 20:52:19 +02003393 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003394 err = mgmt_cmd_complete(sk, hdev->id,
3395 MGMT_OP_ADD_REMOTE_OOB_DATA,
3396 MGMT_STATUS_INVALID_PARAMS,
3397 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003398 goto unlock;
3399 }
3400
Marcel Holtmannec109112014-01-10 02:07:30 -08003401 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003402 cp->addr.type, cp->hash,
3403 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003404 if (err < 0)
3405 status = MGMT_STATUS_FAILED;
3406 else
3407 status = MGMT_STATUS_SUCCESS;
3408
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003409 err = mgmt_cmd_complete(sk, hdev->id,
3410 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3411 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003412 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3413 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003414 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003415 u8 status;
3416
Johan Hedberg86df9202014-10-26 20:52:27 +01003417 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003418 /* Enforce zero-valued 192-bit parameters as
3419 * long as legacy SMP OOB isn't implemented.
3420 */
3421 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3422 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003423 err = mgmt_cmd_complete(sk, hdev->id,
3424 MGMT_OP_ADD_REMOTE_OOB_DATA,
3425 MGMT_STATUS_INVALID_PARAMS,
3426 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003427 goto unlock;
3428 }
3429
Johan Hedberg86df9202014-10-26 20:52:27 +01003430 rand192 = NULL;
3431 hash192 = NULL;
3432 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003433 /* In case one of the P-192 values is set to zero,
3434 * then just disable OOB data for P-192.
3435 */
3436 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3437 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3438 rand192 = NULL;
3439 hash192 = NULL;
3440 } else {
3441 rand192 = cp->rand192;
3442 hash192 = cp->hash192;
3443 }
3444 }
3445
3446 /* In case one of the P-256 values is set to zero, then just
3447 * disable OOB data for P-256.
3448 */
3449 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3450 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3451 rand256 = NULL;
3452 hash256 = NULL;
3453 } else {
3454 rand256 = cp->rand256;
3455 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003456 }
3457
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003458 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003459 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003460 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003461 if (err < 0)
3462 status = MGMT_STATUS_FAILED;
3463 else
3464 status = MGMT_STATUS_SUCCESS;
3465
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003466 err = mgmt_cmd_complete(sk, hdev->id,
3467 MGMT_OP_ADD_REMOTE_OOB_DATA,
3468 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003469 } else {
3470 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003471 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3472 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003473 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003474
Johan Hedbergc19a4952014-11-17 20:52:19 +02003475unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003476 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003477 return err;
3478}
3479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003480static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003481 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003482{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003483 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003484 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003485 int err;
3486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003487 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003488
Johan Hedbergc19a4952014-11-17 20:52:19 +02003489 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003490 return mgmt_cmd_complete(sk, hdev->id,
3491 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3492 MGMT_STATUS_INVALID_PARAMS,
3493 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003494
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003495 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003496
Johan Hedbergeedbd582014-11-15 09:34:23 +02003497 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3498 hci_remote_oob_data_clear(hdev);
3499 status = MGMT_STATUS_SUCCESS;
3500 goto done;
3501 }
3502
Johan Hedberg6928a922014-10-26 20:46:09 +01003503 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003504 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003505 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003506 else
Szymon Janca6785be2012-12-13 15:11:21 +01003507 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003508
Johan Hedbergeedbd582014-11-15 09:34:23 +02003509done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003510 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3511 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003512
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003513 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003514 return err;
3515}
3516
Johan Hedberge68f0722015-11-11 08:30:30 +02003517void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003518{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003519 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003520
Andre Guedes7c307722013-04-30 15:29:28 -03003521 BT_DBG("status %d", status);
3522
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003523 hci_dev_lock(hdev);
3524
Johan Hedberg333ae952015-03-17 13:48:47 +02003525 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003526 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003527 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003528
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003529 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003530 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003531 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003532 }
3533
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003534 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003535}
3536
Johan Hedberg591752a2015-11-11 08:11:24 +02003537static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3538 uint8_t *mgmt_status)
3539{
3540 switch (type) {
3541 case DISCOV_TYPE_LE:
3542 *mgmt_status = mgmt_le_support(hdev);
3543 if (*mgmt_status)
3544 return false;
3545 break;
3546 case DISCOV_TYPE_INTERLEAVED:
3547 *mgmt_status = mgmt_le_support(hdev);
3548 if (*mgmt_status)
3549 return false;
3550 /* Intentional fall-through */
3551 case DISCOV_TYPE_BREDR:
3552 *mgmt_status = mgmt_bredr_support(hdev);
3553 if (*mgmt_status)
3554 return false;
3555 break;
3556 default:
3557 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3558 return false;
3559 }
3560
3561 return true;
3562}
3563
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003564static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003565 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003566{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003567 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003568 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003569 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003570 int err;
3571
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003572 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003573
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003574 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003575
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003576 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003577 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3578 MGMT_STATUS_NOT_POWERED,
3579 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003580 goto failed;
3581 }
3582
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003583 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003584 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003585 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3586 MGMT_STATUS_BUSY, &cp->type,
3587 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003588 goto failed;
3589 }
3590
Johan Hedberg591752a2015-11-11 08:11:24 +02003591 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3592 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3593 status, &cp->type, sizeof(cp->type));
3594 goto failed;
3595 }
3596
Marcel Holtmann22078802014-12-05 11:45:22 +01003597 /* Clear the discovery filter first to free any previously
3598 * allocated memory for the UUID list.
3599 */
3600 hci_discovery_filter_clear(hdev);
3601
Andre Guedes4aab14e2012-02-17 20:39:36 -03003602 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003603 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003604
Johan Hedberge68f0722015-11-11 08:30:30 +02003605 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
3606 if (!cmd) {
3607 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003608 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003609 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003610
Johan Hedberge68f0722015-11-11 08:30:30 +02003611 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003612
3613 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003614 queue_work(hdev->req_workqueue, &hdev->discov_update);
3615 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003616
3617failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003618 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003619 return err;
3620}
3621
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003622static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3623 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003624{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003625 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3626 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003627}
3628
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003629static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3630 void *data, u16 len)
3631{
3632 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003633 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003634 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3635 u16 uuid_count, expected_len;
3636 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003637 int err;
3638
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003639 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003640
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003641 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003642
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003643 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003644 err = mgmt_cmd_complete(sk, hdev->id,
3645 MGMT_OP_START_SERVICE_DISCOVERY,
3646 MGMT_STATUS_NOT_POWERED,
3647 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003648 goto failed;
3649 }
3650
3651 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003652 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003653 err = mgmt_cmd_complete(sk, hdev->id,
3654 MGMT_OP_START_SERVICE_DISCOVERY,
3655 MGMT_STATUS_BUSY, &cp->type,
3656 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003657 goto failed;
3658 }
3659
3660 uuid_count = __le16_to_cpu(cp->uuid_count);
3661 if (uuid_count > max_uuid_count) {
3662 BT_ERR("service_discovery: too big uuid_count value %u",
3663 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003664 err = mgmt_cmd_complete(sk, hdev->id,
3665 MGMT_OP_START_SERVICE_DISCOVERY,
3666 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3667 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003668 goto failed;
3669 }
3670
3671 expected_len = sizeof(*cp) + uuid_count * 16;
3672 if (expected_len != len) {
3673 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3674 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003675 err = mgmt_cmd_complete(sk, hdev->id,
3676 MGMT_OP_START_SERVICE_DISCOVERY,
3677 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3678 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003679 goto failed;
3680 }
3681
Johan Hedberg591752a2015-11-11 08:11:24 +02003682 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3683 err = mgmt_cmd_complete(sk, hdev->id,
3684 MGMT_OP_START_SERVICE_DISCOVERY,
3685 status, &cp->type, sizeof(cp->type));
3686 goto failed;
3687 }
3688
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003689 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003690 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003691 if (!cmd) {
3692 err = -ENOMEM;
3693 goto failed;
3694 }
3695
Johan Hedberg2922a942014-12-05 13:36:06 +02003696 cmd->cmd_complete = service_discovery_cmd_complete;
3697
Marcel Holtmann22078802014-12-05 11:45:22 +01003698 /* Clear the discovery filter first to free any previously
3699 * allocated memory for the UUID list.
3700 */
3701 hci_discovery_filter_clear(hdev);
3702
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003703 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003704 hdev->discovery.type = cp->type;
3705 hdev->discovery.rssi = cp->rssi;
3706 hdev->discovery.uuid_count = uuid_count;
3707
3708 if (uuid_count > 0) {
3709 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3710 GFP_KERNEL);
3711 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003712 err = mgmt_cmd_complete(sk, hdev->id,
3713 MGMT_OP_START_SERVICE_DISCOVERY,
3714 MGMT_STATUS_FAILED,
3715 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003716 mgmt_pending_remove(cmd);
3717 goto failed;
3718 }
3719 }
3720
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003721 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003722 queue_work(hdev->req_workqueue, &hdev->discov_update);
3723 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003724
3725failed:
3726 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003727 return err;
3728}
3729
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003730void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003731{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003732 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003733
Andre Guedes0e05bba2013-04-30 15:29:33 -03003734 BT_DBG("status %d", status);
3735
3736 hci_dev_lock(hdev);
3737
Johan Hedberg333ae952015-03-17 13:48:47 +02003738 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003739 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003740 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003741 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003742 }
3743
Andre Guedes0e05bba2013-04-30 15:29:33 -03003744 hci_dev_unlock(hdev);
3745}
3746
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003747static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003748 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003749{
Johan Hedbergd9306502012-02-20 23:25:18 +02003750 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003751 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003752 int err;
3753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003754 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003755
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003756 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003757
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003758 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003759 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3760 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3761 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003762 goto unlock;
3763 }
3764
3765 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003766 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3767 MGMT_STATUS_INVALID_PARAMS,
3768 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003769 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003770 }
3771
Johan Hedberg2922a942014-12-05 13:36:06 +02003772 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003773 if (!cmd) {
3774 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003775 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003776 }
3777
Johan Hedberg2922a942014-12-05 13:36:06 +02003778 cmd->cmd_complete = generic_cmd_complete;
3779
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003780 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3781 queue_work(hdev->req_workqueue, &hdev->discov_update);
3782 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003783
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003784unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003785 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003786 return err;
3787}
3788
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003789static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003790 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003791{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003792 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003793 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003794 int err;
3795
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003796 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003797
Johan Hedberg561aafb2012-01-04 13:31:59 +02003798 hci_dev_lock(hdev);
3799
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003800 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003801 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3802 MGMT_STATUS_FAILED, &cp->addr,
3803 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003804 goto failed;
3805 }
3806
Johan Hedberga198e7b2012-02-17 14:27:06 +02003807 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003808 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003809 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3810 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3811 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003812 goto failed;
3813 }
3814
3815 if (cp->name_known) {
3816 e->name_state = NAME_KNOWN;
3817 list_del(&e->list);
3818 } else {
3819 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003820 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003821 }
3822
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003823 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3824 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003825
3826failed:
3827 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003828 return err;
3829}
3830
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003831static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003832 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003833{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003834 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003835 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003836 int err;
3837
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003838 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003839
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003840 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003841 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3842 MGMT_STATUS_INVALID_PARAMS,
3843 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003844
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003845 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003846
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003847 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3848 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003849 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003850 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003851 goto done;
3852 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003853
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003854 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3855 sk);
3856 status = MGMT_STATUS_SUCCESS;
3857
3858done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003859 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3860 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003861
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003862 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003863
3864 return err;
3865}
3866
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003867static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003868 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003869{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003870 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003871 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003872 int err;
3873
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003874 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003875
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003876 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003877 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3878 MGMT_STATUS_INVALID_PARAMS,
3879 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003880
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003881 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003882
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003883 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3884 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003885 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003886 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003887 goto done;
3888 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003889
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003890 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3891 sk);
3892 status = MGMT_STATUS_SUCCESS;
3893
3894done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003895 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3896 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003897
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003898 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003899
3900 return err;
3901}
3902
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003903static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3904 u16 len)
3905{
3906 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003907 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003908 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003909 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003910
3911 BT_DBG("%s", hdev->name);
3912
Szymon Jancc72d4b82012-03-16 16:02:57 +01003913 source = __le16_to_cpu(cp->source);
3914
3915 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003916 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3917 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003918
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003919 hci_dev_lock(hdev);
3920
Szymon Jancc72d4b82012-03-16 16:02:57 +01003921 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003922 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3923 hdev->devid_product = __le16_to_cpu(cp->product);
3924 hdev->devid_version = __le16_to_cpu(cp->version);
3925
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003926 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3927 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003928
Johan Hedberg890ea892013-03-15 17:06:52 -05003929 hci_req_init(&req, hdev);
3930 update_eir(&req);
3931 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003932
3933 hci_dev_unlock(hdev);
3934
3935 return err;
3936}
3937
Arman Uguray24b4f382015-03-23 15:57:12 -07003938static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3939 u16 opcode)
3940{
3941 BT_DBG("status %d", status);
3942}
3943
Marcel Holtmann1904a852015-01-11 13:50:44 -08003944static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3945 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003946{
3947 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003948 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003949 u8 instance;
3950 struct adv_info *adv_instance;
3951 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003952
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303953 hci_dev_lock(hdev);
3954
Johan Hedberg4375f102013-09-25 13:26:10 +03003955 if (status) {
3956 u8 mgmt_err = mgmt_status(status);
3957
3958 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3959 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303960 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003961 }
3962
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003963 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003964 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003965 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003966 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003967
Johan Hedberg4375f102013-09-25 13:26:10 +03003968 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3969 &match);
3970
3971 new_settings(hdev, match.sk);
3972
3973 if (match.sk)
3974 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303975
Arman Uguray24b4f382015-03-23 15:57:12 -07003976 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003977 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003978 */
3979 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003980 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
3981 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003982 goto unlock;
3983
Florian Grandel7816b822015-06-18 03:16:45 +02003984 instance = hdev->cur_adv_instance;
3985 if (!instance) {
3986 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3987 struct adv_info, list);
3988 if (!adv_instance)
3989 goto unlock;
3990
3991 instance = adv_instance->instance;
3992 }
3993
Arman Uguray24b4f382015-03-23 15:57:12 -07003994 hci_req_init(&req, hdev);
3995
Johan Hedbergf2252572015-11-18 12:49:20 +02003996 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003997
Florian Grandel7816b822015-06-18 03:16:45 +02003998 if (!err)
3999 err = hci_req_run(&req, enable_advertising_instance);
4000
4001 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07004002 BT_ERR("Failed to re-configure advertising");
4003
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304004unlock:
4005 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004006}
4007
Marcel Holtmann21b51872013-10-10 09:47:53 -07004008static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4009 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004010{
4011 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004012 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004013 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004014 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004015 int err;
4016
4017 BT_DBG("request for %s", hdev->name);
4018
Johan Hedberge6fe7982013-10-02 15:45:22 +03004019 status = mgmt_le_support(hdev);
4020 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004021 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4022 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004023
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004024 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004025 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4026 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004027
4028 hci_dev_lock(hdev);
4029
4030 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004031
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004032 /* The following conditions are ones which mean that we should
4033 * not do any HCI communication but directly send a mgmt
4034 * response to user space (after toggling the flag if
4035 * necessary).
4036 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004037 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004038 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4039 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004040 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004041 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004042 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004043 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004044
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004045 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004046 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004047 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004048 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004049 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004050 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004051 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004052 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004053 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004054 }
4055
4056 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4057 if (err < 0)
4058 goto unlock;
4059
4060 if (changed)
4061 err = new_settings(hdev, sk);
4062
4063 goto unlock;
4064 }
4065
Johan Hedberg333ae952015-03-17 13:48:47 +02004066 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4067 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004068 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4069 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004070 goto unlock;
4071 }
4072
4073 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4074 if (!cmd) {
4075 err = -ENOMEM;
4076 goto unlock;
4077 }
4078
4079 hci_req_init(&req, hdev);
4080
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004081 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004082 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004083 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004084 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004085
Florian Grandel7816b822015-06-18 03:16:45 +02004086 cancel_adv_timeout(hdev);
4087
Arman Uguray24b4f382015-03-23 15:57:12 -07004088 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004089 /* Switch to instance "0" for the Set Advertising setting.
4090 * We cannot use update_[adv|scan_rsp]_data() here as the
4091 * HCI_ADVERTISING flag is not yet set.
4092 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004093 __hci_req_update_adv_data(&req, 0x00);
4094 __hci_req_update_scan_rsp_data(&req, 0x00);
4095 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004096 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004097 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004098 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004099
4100 err = hci_req_run(&req, set_advertising_complete);
4101 if (err < 0)
4102 mgmt_pending_remove(cmd);
4103
4104unlock:
4105 hci_dev_unlock(hdev);
4106 return err;
4107}
4108
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004109static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4110 void *data, u16 len)
4111{
4112 struct mgmt_cp_set_static_address *cp = data;
4113 int err;
4114
4115 BT_DBG("%s", hdev->name);
4116
Marcel Holtmann62af4442013-10-02 22:10:32 -07004117 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004118 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4119 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004120
4121 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004122 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4123 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004124
4125 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4126 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004127 return mgmt_cmd_status(sk, hdev->id,
4128 MGMT_OP_SET_STATIC_ADDRESS,
4129 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004130
4131 /* Two most significant bits shall be set */
4132 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004133 return mgmt_cmd_status(sk, hdev->id,
4134 MGMT_OP_SET_STATIC_ADDRESS,
4135 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004136 }
4137
4138 hci_dev_lock(hdev);
4139
4140 bacpy(&hdev->static_addr, &cp->bdaddr);
4141
Marcel Holtmann93690c22015-03-06 10:11:21 -08004142 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4143 if (err < 0)
4144 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004145
Marcel Holtmann93690c22015-03-06 10:11:21 -08004146 err = new_settings(hdev, sk);
4147
4148unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004149 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004150 return err;
4151}
4152
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004153static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4154 void *data, u16 len)
4155{
4156 struct mgmt_cp_set_scan_params *cp = data;
4157 __u16 interval, window;
4158 int err;
4159
4160 BT_DBG("%s", hdev->name);
4161
4162 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004163 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4164 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004165
4166 interval = __le16_to_cpu(cp->interval);
4167
4168 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004169 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4170 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004171
4172 window = __le16_to_cpu(cp->window);
4173
4174 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004175 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4176 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004177
Marcel Holtmann899e1072013-10-14 09:55:32 -07004178 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004179 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4180 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004181
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004182 hci_dev_lock(hdev);
4183
4184 hdev->le_scan_interval = interval;
4185 hdev->le_scan_window = window;
4186
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004187 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4188 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004189
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004190 /* If background scan is running, restart it so new parameters are
4191 * loaded.
4192 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004193 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004194 hdev->discovery.state == DISCOVERY_STOPPED) {
4195 struct hci_request req;
4196
4197 hci_req_init(&req, hdev);
4198
4199 hci_req_add_le_scan_disable(&req);
4200 hci_req_add_le_passive_scan(&req);
4201
4202 hci_req_run(&req, NULL);
4203 }
4204
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004205 hci_dev_unlock(hdev);
4206
4207 return err;
4208}
4209
Marcel Holtmann1904a852015-01-11 13:50:44 -08004210static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4211 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004212{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004213 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004214
4215 BT_DBG("status 0x%02x", status);
4216
4217 hci_dev_lock(hdev);
4218
Johan Hedberg333ae952015-03-17 13:48:47 +02004219 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004220 if (!cmd)
4221 goto unlock;
4222
4223 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004224 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4225 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004226 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004227 struct mgmt_mode *cp = cmd->param;
4228
4229 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004230 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004231 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004232 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004233
Johan Hedberg33e38b32013-03-15 17:07:05 -05004234 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4235 new_settings(hdev, cmd->sk);
4236 }
4237
4238 mgmt_pending_remove(cmd);
4239
4240unlock:
4241 hci_dev_unlock(hdev);
4242}
4243
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004244static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004245 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004246{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004247 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004248 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004249 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004250 int err;
4251
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004252 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004253
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004254 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004255 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004256 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4257 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004258
Johan Hedberga7e80f22013-01-09 16:05:19 +02004259 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004260 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4261 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004262
Antti Julkuf6422ec2011-06-22 13:11:56 +03004263 hci_dev_lock(hdev);
4264
Johan Hedberg333ae952015-03-17 13:48:47 +02004265 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004266 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4267 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004268 goto unlock;
4269 }
4270
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004271 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004272 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4273 hdev);
4274 goto unlock;
4275 }
4276
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004277 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004278 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004279 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4280 hdev);
4281 new_settings(hdev, sk);
4282 goto unlock;
4283 }
4284
Johan Hedberg33e38b32013-03-15 17:07:05 -05004285 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4286 data, len);
4287 if (!cmd) {
4288 err = -ENOMEM;
4289 goto unlock;
4290 }
4291
4292 hci_req_init(&req, hdev);
4293
Johan Hedberg406d7802013-03-15 17:07:09 -05004294 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004295
4296 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004297 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004298 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4299 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004300 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004301 }
4302
Johan Hedberg33e38b32013-03-15 17:07:05 -05004303unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004304 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004305
Antti Julkuf6422ec2011-06-22 13:11:56 +03004306 return err;
4307}
4308
Marcel Holtmann1904a852015-01-11 13:50:44 -08004309static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004310{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004311 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004312
4313 BT_DBG("status 0x%02x", status);
4314
4315 hci_dev_lock(hdev);
4316
Johan Hedberg333ae952015-03-17 13:48:47 +02004317 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004318 if (!cmd)
4319 goto unlock;
4320
4321 if (status) {
4322 u8 mgmt_err = mgmt_status(status);
4323
4324 /* We need to restore the flag if related HCI commands
4325 * failed.
4326 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004327 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004328
Johan Hedberga69e8372015-03-06 21:08:53 +02004329 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004330 } else {
4331 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4332 new_settings(hdev, cmd->sk);
4333 }
4334
4335 mgmt_pending_remove(cmd);
4336
4337unlock:
4338 hci_dev_unlock(hdev);
4339}
4340
4341static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4342{
4343 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004344 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004345 struct hci_request req;
4346 int err;
4347
4348 BT_DBG("request for %s", hdev->name);
4349
4350 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004351 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4352 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004353
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004354 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004355 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4356 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004357
4358 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004359 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4360 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004361
4362 hci_dev_lock(hdev);
4363
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004364 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004365 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4366 goto unlock;
4367 }
4368
4369 if (!hdev_is_powered(hdev)) {
4370 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004371 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4372 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4373 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4374 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4375 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004376 }
4377
Marcel Holtmannce05d602015-03-13 02:11:03 -07004378 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004379
4380 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4381 if (err < 0)
4382 goto unlock;
4383
4384 err = new_settings(hdev, sk);
4385 goto unlock;
4386 }
4387
4388 /* Reject disabling when powered on */
4389 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004390 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4391 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004392 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004393 } else {
4394 /* When configuring a dual-mode controller to operate
4395 * with LE only and using a static address, then switching
4396 * BR/EDR back on is not allowed.
4397 *
4398 * Dual-mode controllers shall operate with the public
4399 * address as its identity address for BR/EDR and LE. So
4400 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004401 *
4402 * The same restrictions applies when secure connections
4403 * has been enabled. For BR/EDR this is a controller feature
4404 * while for LE it is a host stack feature. This means that
4405 * switching BR/EDR back on when secure connections has been
4406 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004407 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004408 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004409 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004410 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004411 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4412 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004413 goto unlock;
4414 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004415 }
4416
Johan Hedberg333ae952015-03-17 13:48:47 +02004417 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004418 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4419 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004420 goto unlock;
4421 }
4422
4423 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4424 if (!cmd) {
4425 err = -ENOMEM;
4426 goto unlock;
4427 }
4428
Johan Hedbergf2252572015-11-18 12:49:20 +02004429 /* We need to flip the bit already here so that
4430 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004431 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004432 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004433
4434 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004435
Johan Hedberg432df052014-08-01 11:13:31 +03004436 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004437 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004438
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004439 /* Since only the advertising data flags will change, there
4440 * is no need to update the scan response data.
4441 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004442 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004443
Johan Hedberg0663ca22013-10-02 13:43:14 +03004444 err = hci_req_run(&req, set_bredr_complete);
4445 if (err < 0)
4446 mgmt_pending_remove(cmd);
4447
4448unlock:
4449 hci_dev_unlock(hdev);
4450 return err;
4451}
4452
Johan Hedberga1443f52015-01-23 15:42:46 +02004453static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4454{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004455 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004456 struct mgmt_mode *cp;
4457
4458 BT_DBG("%s status %u", hdev->name, status);
4459
4460 hci_dev_lock(hdev);
4461
Johan Hedberg333ae952015-03-17 13:48:47 +02004462 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004463 if (!cmd)
4464 goto unlock;
4465
4466 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004467 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4468 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004469 goto remove;
4470 }
4471
4472 cp = cmd->param;
4473
4474 switch (cp->val) {
4475 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004476 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4477 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004478 break;
4479 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004480 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004481 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004482 break;
4483 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004484 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4485 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004486 break;
4487 }
4488
4489 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4490 new_settings(hdev, cmd->sk);
4491
4492remove:
4493 mgmt_pending_remove(cmd);
4494unlock:
4495 hci_dev_unlock(hdev);
4496}
4497
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004498static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4499 void *data, u16 len)
4500{
4501 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004502 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004503 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004504 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004505 int err;
4506
4507 BT_DBG("request for %s", hdev->name);
4508
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004509 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004510 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004511 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4512 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004513
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004514 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004515 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004516 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004517 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4518 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004519
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004520 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004521 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004522 MGMT_STATUS_INVALID_PARAMS);
4523
4524 hci_dev_lock(hdev);
4525
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004526 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004527 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004528 bool changed;
4529
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004530 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004531 changed = !hci_dev_test_and_set_flag(hdev,
4532 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004533 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004534 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004535 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004536 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004537 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004538 changed = hci_dev_test_and_clear_flag(hdev,
4539 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004540 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004541 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004542
4543 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4544 if (err < 0)
4545 goto failed;
4546
4547 if (changed)
4548 err = new_settings(hdev, sk);
4549
4550 goto failed;
4551 }
4552
Johan Hedberg333ae952015-03-17 13:48:47 +02004553 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004554 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4555 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004556 goto failed;
4557 }
4558
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004559 val = !!cp->val;
4560
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004561 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4562 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004563 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4564 goto failed;
4565 }
4566
4567 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4568 if (!cmd) {
4569 err = -ENOMEM;
4570 goto failed;
4571 }
4572
Johan Hedberga1443f52015-01-23 15:42:46 +02004573 hci_req_init(&req, hdev);
4574 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4575 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004576 if (err < 0) {
4577 mgmt_pending_remove(cmd);
4578 goto failed;
4579 }
4580
4581failed:
4582 hci_dev_unlock(hdev);
4583 return err;
4584}
4585
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004586static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4587 void *data, u16 len)
4588{
4589 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004590 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004591 int err;
4592
4593 BT_DBG("request for %s", hdev->name);
4594
Johan Hedbergb97109792014-06-24 14:00:28 +03004595 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004596 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4597 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004598
4599 hci_dev_lock(hdev);
4600
4601 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004602 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004603 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004604 changed = hci_dev_test_and_clear_flag(hdev,
4605 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004606
Johan Hedbergb97109792014-06-24 14:00:28 +03004607 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004608 use_changed = !hci_dev_test_and_set_flag(hdev,
4609 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004610 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004611 use_changed = hci_dev_test_and_clear_flag(hdev,
4612 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004613
4614 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004615 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004616 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4617 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4618 sizeof(mode), &mode);
4619 }
4620
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004621 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4622 if (err < 0)
4623 goto unlock;
4624
4625 if (changed)
4626 err = new_settings(hdev, sk);
4627
4628unlock:
4629 hci_dev_unlock(hdev);
4630 return err;
4631}
4632
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004633static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4634 u16 len)
4635{
4636 struct mgmt_cp_set_privacy *cp = cp_data;
4637 bool changed;
4638 int err;
4639
4640 BT_DBG("request for %s", hdev->name);
4641
4642 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004643 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4644 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004645
4646 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004647 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4648 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004649
4650 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004651 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4652 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004653
4654 hci_dev_lock(hdev);
4655
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004656 /* If user space supports this command it is also expected to
4657 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4658 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004659 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004660
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004661 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004662 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004663 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004664 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004665 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004666 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004667 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004668 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004669 }
4670
4671 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4672 if (err < 0)
4673 goto unlock;
4674
4675 if (changed)
4676 err = new_settings(hdev, sk);
4677
4678unlock:
4679 hci_dev_unlock(hdev);
4680 return err;
4681}
4682
Johan Hedberg41edf162014-02-18 10:19:35 +02004683static bool irk_is_valid(struct mgmt_irk_info *irk)
4684{
4685 switch (irk->addr.type) {
4686 case BDADDR_LE_PUBLIC:
4687 return true;
4688
4689 case BDADDR_LE_RANDOM:
4690 /* Two most significant bits shall be set */
4691 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4692 return false;
4693 return true;
4694 }
4695
4696 return false;
4697}
4698
4699static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4700 u16 len)
4701{
4702 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004703 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4704 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004705 u16 irk_count, expected_len;
4706 int i, err;
4707
4708 BT_DBG("request for %s", hdev->name);
4709
4710 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004711 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4712 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004713
4714 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004715 if (irk_count > max_irk_count) {
4716 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004717 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4718 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004719 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004720
4721 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4722 if (expected_len != len) {
4723 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004724 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004725 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4726 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004727 }
4728
4729 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4730
4731 for (i = 0; i < irk_count; i++) {
4732 struct mgmt_irk_info *key = &cp->irks[i];
4733
4734 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004735 return mgmt_cmd_status(sk, hdev->id,
4736 MGMT_OP_LOAD_IRKS,
4737 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004738 }
4739
4740 hci_dev_lock(hdev);
4741
4742 hci_smp_irks_clear(hdev);
4743
4744 for (i = 0; i < irk_count; i++) {
4745 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004746
Johan Hedberg85813a72015-10-21 18:02:59 +03004747 hci_add_irk(hdev, &irk->addr.bdaddr,
4748 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004749 BDADDR_ANY);
4750 }
4751
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004752 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004753
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004754 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004755
4756 hci_dev_unlock(hdev);
4757
4758 return err;
4759}
4760
Johan Hedberg3f706b72013-01-20 14:27:16 +02004761static bool ltk_is_valid(struct mgmt_ltk_info *key)
4762{
4763 if (key->master != 0x00 && key->master != 0x01)
4764 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004765
4766 switch (key->addr.type) {
4767 case BDADDR_LE_PUBLIC:
4768 return true;
4769
4770 case BDADDR_LE_RANDOM:
4771 /* Two most significant bits shall be set */
4772 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4773 return false;
4774 return true;
4775 }
4776
4777 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004778}
4779
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004780static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004781 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004782{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004783 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004784 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4785 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004786 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004787 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004788
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004789 BT_DBG("request for %s", hdev->name);
4790
4791 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004792 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4793 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004794
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004795 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004796 if (key_count > max_key_count) {
4797 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4799 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004800 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004801
4802 expected_len = sizeof(*cp) + key_count *
4803 sizeof(struct mgmt_ltk_info);
4804 if (expected_len != len) {
4805 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004806 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004807 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4808 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004809 }
4810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004811 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004812
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004813 for (i = 0; i < key_count; i++) {
4814 struct mgmt_ltk_info *key = &cp->keys[i];
4815
Johan Hedberg3f706b72013-01-20 14:27:16 +02004816 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004817 return mgmt_cmd_status(sk, hdev->id,
4818 MGMT_OP_LOAD_LONG_TERM_KEYS,
4819 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004820 }
4821
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004822 hci_dev_lock(hdev);
4823
4824 hci_smp_ltks_clear(hdev);
4825
4826 for (i = 0; i < key_count; i++) {
4827 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004828 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004829
Johan Hedberg61b43352014-05-29 19:36:53 +03004830 switch (key->type) {
4831 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004832 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004833 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004834 break;
4835 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004836 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004837 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004838 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004839 case MGMT_LTK_P256_UNAUTH:
4840 authenticated = 0x00;
4841 type = SMP_LTK_P256;
4842 break;
4843 case MGMT_LTK_P256_AUTH:
4844 authenticated = 0x01;
4845 type = SMP_LTK_P256;
4846 break;
4847 case MGMT_LTK_P256_DEBUG:
4848 authenticated = 0x00;
4849 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004850 default:
4851 continue;
4852 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004853
Johan Hedberg85813a72015-10-21 18:02:59 +03004854 hci_add_ltk(hdev, &key->addr.bdaddr,
4855 le_addr_type(key->addr.type), type, authenticated,
4856 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004857 }
4858
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004859 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004860 NULL, 0);
4861
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004862 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004863
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004864 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004865}
4866
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004867static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004868{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004869 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004870 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004871 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004872
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004873 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004874
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004875 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004876 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004877 rp.tx_power = conn->tx_power;
4878 rp.max_tx_power = conn->max_tx_power;
4879 } else {
4880 rp.rssi = HCI_RSSI_INVALID;
4881 rp.tx_power = HCI_TX_POWER_INVALID;
4882 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004883 }
4884
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004885 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4886 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004887
4888 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004889 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004890
4891 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004892}
4893
Marcel Holtmann1904a852015-01-11 13:50:44 -08004894static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4895 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004896{
4897 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004898 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004899 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004900 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004901 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004902
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004903 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004904
4905 hci_dev_lock(hdev);
4906
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004907 /* Commands sent in request are either Read RSSI or Read Transmit Power
4908 * Level so we check which one was last sent to retrieve connection
4909 * handle. Both commands have handle as first parameter so it's safe to
4910 * cast data on the same command struct.
4911 *
4912 * First command sent is always Read RSSI and we fail only if it fails.
4913 * In other case we simply override error to indicate success as we
4914 * already remembered if TX power value is actually valid.
4915 */
4916 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4917 if (!cp) {
4918 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004919 status = MGMT_STATUS_SUCCESS;
4920 } else {
4921 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004922 }
4923
4924 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004925 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004926 goto unlock;
4927 }
4928
4929 handle = __le16_to_cpu(cp->handle);
4930 conn = hci_conn_hash_lookup_handle(hdev, handle);
4931 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004932 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004933 goto unlock;
4934 }
4935
Johan Hedberg333ae952015-03-17 13:48:47 +02004936 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004937 if (!cmd)
4938 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004939
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004940 cmd->cmd_complete(cmd, status);
4941 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004942
4943unlock:
4944 hci_dev_unlock(hdev);
4945}
4946
4947static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4948 u16 len)
4949{
4950 struct mgmt_cp_get_conn_info *cp = data;
4951 struct mgmt_rp_get_conn_info rp;
4952 struct hci_conn *conn;
4953 unsigned long conn_info_age;
4954 int err = 0;
4955
4956 BT_DBG("%s", hdev->name);
4957
4958 memset(&rp, 0, sizeof(rp));
4959 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4960 rp.addr.type = cp->addr.type;
4961
4962 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004963 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4964 MGMT_STATUS_INVALID_PARAMS,
4965 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004966
4967 hci_dev_lock(hdev);
4968
4969 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004970 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4971 MGMT_STATUS_NOT_POWERED, &rp,
4972 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004973 goto unlock;
4974 }
4975
4976 if (cp->addr.type == BDADDR_BREDR)
4977 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4978 &cp->addr.bdaddr);
4979 else
4980 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4981
4982 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004983 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4984 MGMT_STATUS_NOT_CONNECTED, &rp,
4985 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004986 goto unlock;
4987 }
4988
Johan Hedberg333ae952015-03-17 13:48:47 +02004989 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004990 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4991 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004992 goto unlock;
4993 }
4994
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004995 /* To avoid client trying to guess when to poll again for information we
4996 * calculate conn info age as random value between min/max set in hdev.
4997 */
4998 conn_info_age = hdev->conn_info_min_age +
4999 prandom_u32_max(hdev->conn_info_max_age -
5000 hdev->conn_info_min_age);
5001
5002 /* Query controller to refresh cached values if they are too old or were
5003 * never read.
5004 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005005 if (time_after(jiffies, conn->conn_info_timestamp +
5006 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005007 !conn->conn_info_timestamp) {
5008 struct hci_request req;
5009 struct hci_cp_read_tx_power req_txp_cp;
5010 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005011 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005012
5013 hci_req_init(&req, hdev);
5014 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5015 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5016 &req_rssi_cp);
5017
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005018 /* For LE links TX power does not change thus we don't need to
5019 * query for it once value is known.
5020 */
5021 if (!bdaddr_type_is_le(cp->addr.type) ||
5022 conn->tx_power == HCI_TX_POWER_INVALID) {
5023 req_txp_cp.handle = cpu_to_le16(conn->handle);
5024 req_txp_cp.type = 0x00;
5025 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5026 sizeof(req_txp_cp), &req_txp_cp);
5027 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005028
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005029 /* Max TX power needs to be read only once per connection */
5030 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5031 req_txp_cp.handle = cpu_to_le16(conn->handle);
5032 req_txp_cp.type = 0x01;
5033 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5034 sizeof(req_txp_cp), &req_txp_cp);
5035 }
5036
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005037 err = hci_req_run(&req, conn_info_refresh_complete);
5038 if (err < 0)
5039 goto unlock;
5040
5041 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5042 data, len);
5043 if (!cmd) {
5044 err = -ENOMEM;
5045 goto unlock;
5046 }
5047
5048 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005049 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005050 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005051
5052 conn->conn_info_timestamp = jiffies;
5053 } else {
5054 /* Cache is valid, just reply with values cached in hci_conn */
5055 rp.rssi = conn->rssi;
5056 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005057 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005058
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005059 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5060 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005061 }
5062
5063unlock:
5064 hci_dev_unlock(hdev);
5065 return err;
5066}
5067
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005068static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005069{
5070 struct hci_conn *conn = cmd->user_data;
5071 struct mgmt_rp_get_clock_info rp;
5072 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005073 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005074
5075 memset(&rp, 0, sizeof(rp));
5076 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5077
5078 if (status)
5079 goto complete;
5080
5081 hdev = hci_dev_get(cmd->index);
5082 if (hdev) {
5083 rp.local_clock = cpu_to_le32(hdev->clock);
5084 hci_dev_put(hdev);
5085 }
5086
5087 if (conn) {
5088 rp.piconet_clock = cpu_to_le32(conn->clock);
5089 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5090 }
5091
5092complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005093 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5094 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005095
5096 if (conn) {
5097 hci_conn_drop(conn);
5098 hci_conn_put(conn);
5099 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005100
5101 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005102}
5103
Marcel Holtmann1904a852015-01-11 13:50:44 -08005104static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005105{
Johan Hedberg95868422014-06-28 17:54:07 +03005106 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005107 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005108 struct hci_conn *conn;
5109
5110 BT_DBG("%s status %u", hdev->name, status);
5111
5112 hci_dev_lock(hdev);
5113
5114 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5115 if (!hci_cp)
5116 goto unlock;
5117
5118 if (hci_cp->which) {
5119 u16 handle = __le16_to_cpu(hci_cp->handle);
5120 conn = hci_conn_hash_lookup_handle(hdev, handle);
5121 } else {
5122 conn = NULL;
5123 }
5124
Johan Hedberg333ae952015-03-17 13:48:47 +02005125 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005126 if (!cmd)
5127 goto unlock;
5128
Johan Hedberg69487372014-12-05 13:36:07 +02005129 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005130 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005131
5132unlock:
5133 hci_dev_unlock(hdev);
5134}
5135
5136static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5137 u16 len)
5138{
5139 struct mgmt_cp_get_clock_info *cp = data;
5140 struct mgmt_rp_get_clock_info rp;
5141 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005142 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005143 struct hci_request req;
5144 struct hci_conn *conn;
5145 int err;
5146
5147 BT_DBG("%s", hdev->name);
5148
5149 memset(&rp, 0, sizeof(rp));
5150 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5151 rp.addr.type = cp->addr.type;
5152
5153 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005154 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5155 MGMT_STATUS_INVALID_PARAMS,
5156 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005157
5158 hci_dev_lock(hdev);
5159
5160 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005161 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5162 MGMT_STATUS_NOT_POWERED, &rp,
5163 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005164 goto unlock;
5165 }
5166
5167 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5168 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5169 &cp->addr.bdaddr);
5170 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005171 err = mgmt_cmd_complete(sk, hdev->id,
5172 MGMT_OP_GET_CLOCK_INFO,
5173 MGMT_STATUS_NOT_CONNECTED,
5174 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005175 goto unlock;
5176 }
5177 } else {
5178 conn = NULL;
5179 }
5180
5181 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5182 if (!cmd) {
5183 err = -ENOMEM;
5184 goto unlock;
5185 }
5186
Johan Hedberg69487372014-12-05 13:36:07 +02005187 cmd->cmd_complete = clock_info_cmd_complete;
5188
Johan Hedberg95868422014-06-28 17:54:07 +03005189 hci_req_init(&req, hdev);
5190
5191 memset(&hci_cp, 0, sizeof(hci_cp));
5192 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5193
5194 if (conn) {
5195 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005196 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005197
5198 hci_cp.handle = cpu_to_le16(conn->handle);
5199 hci_cp.which = 0x01; /* Piconet clock */
5200 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5201 }
5202
5203 err = hci_req_run(&req, get_clock_info_complete);
5204 if (err < 0)
5205 mgmt_pending_remove(cmd);
5206
5207unlock:
5208 hci_dev_unlock(hdev);
5209 return err;
5210}
5211
Johan Hedberg5a154e62014-12-19 22:26:02 +02005212static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5213{
5214 struct hci_conn *conn;
5215
5216 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5217 if (!conn)
5218 return false;
5219
5220 if (conn->dst_type != type)
5221 return false;
5222
5223 if (conn->state != BT_CONNECTED)
5224 return false;
5225
5226 return true;
5227}
5228
5229/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005230static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005231 u8 addr_type, u8 auto_connect)
5232{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005233 struct hci_conn_params *params;
5234
5235 params = hci_conn_params_add(hdev, addr, addr_type);
5236 if (!params)
5237 return -EIO;
5238
5239 if (params->auto_connect == auto_connect)
5240 return 0;
5241
5242 list_del_init(&params->action);
5243
5244 switch (auto_connect) {
5245 case HCI_AUTO_CONN_DISABLED:
5246 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005247 /* If auto connect is being disabled when we're trying to
5248 * connect to device, keep connecting.
5249 */
5250 if (params->explicit_connect)
5251 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005252 break;
5253 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005254 if (params->explicit_connect)
5255 list_add(&params->action, &hdev->pend_le_conns);
5256 else
5257 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005258 break;
5259 case HCI_AUTO_CONN_DIRECT:
5260 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005261 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005262 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005263 break;
5264 }
5265
5266 params->auto_connect = auto_connect;
5267
5268 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5269 auto_connect);
5270
5271 return 0;
5272}
5273
Marcel Holtmann8afef092014-06-29 22:28:34 +02005274static void device_added(struct sock *sk, struct hci_dev *hdev,
5275 bdaddr_t *bdaddr, u8 type, u8 action)
5276{
5277 struct mgmt_ev_device_added ev;
5278
5279 bacpy(&ev.addr.bdaddr, bdaddr);
5280 ev.addr.type = type;
5281 ev.action = action;
5282
5283 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5284}
5285
Marcel Holtmann2faade52014-06-29 19:44:03 +02005286static int add_device(struct sock *sk, struct hci_dev *hdev,
5287 void *data, u16 len)
5288{
5289 struct mgmt_cp_add_device *cp = data;
5290 u8 auto_conn, addr_type;
5291 int err;
5292
5293 BT_DBG("%s", hdev->name);
5294
Johan Hedberg66593582014-07-09 12:59:14 +03005295 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005296 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005297 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5298 MGMT_STATUS_INVALID_PARAMS,
5299 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005300
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005301 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005302 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5303 MGMT_STATUS_INVALID_PARAMS,
5304 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005305
5306 hci_dev_lock(hdev);
5307
Johan Hedberg66593582014-07-09 12:59:14 +03005308 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005309 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005310 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005311 err = mgmt_cmd_complete(sk, hdev->id,
5312 MGMT_OP_ADD_DEVICE,
5313 MGMT_STATUS_INVALID_PARAMS,
5314 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005315 goto unlock;
5316 }
5317
5318 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5319 cp->addr.type);
5320 if (err)
5321 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005322
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005323 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005324
Johan Hedberg66593582014-07-09 12:59:14 +03005325 goto added;
5326 }
5327
Johan Hedberg85813a72015-10-21 18:02:59 +03005328 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005329
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005330 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005331 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005332 else if (cp->action == 0x01)
5333 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005334 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005335 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005336
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005337 /* Kernel internally uses conn_params with resolvable private
5338 * address, but Add Device allows only identity addresses.
5339 * Make sure it is enforced before calling
5340 * hci_conn_params_lookup.
5341 */
5342 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005343 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5344 MGMT_STATUS_INVALID_PARAMS,
5345 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005346 goto unlock;
5347 }
5348
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005349 /* If the connection parameters don't exist for this device,
5350 * they will be created and configured with defaults.
5351 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005352 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005353 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005354 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5355 MGMT_STATUS_FAILED, &cp->addr,
5356 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005357 goto unlock;
5358 }
5359
Johan Hedberg51d7a942015-11-11 08:11:18 +02005360 hci_update_background_scan(hdev);
5361
Johan Hedberg66593582014-07-09 12:59:14 +03005362added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005363 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5364
Johan Hedberg51d7a942015-11-11 08:11:18 +02005365 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5366 MGMT_STATUS_SUCCESS, &cp->addr,
5367 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005368
5369unlock:
5370 hci_dev_unlock(hdev);
5371 return err;
5372}
5373
Marcel Holtmann8afef092014-06-29 22:28:34 +02005374static void device_removed(struct sock *sk, struct hci_dev *hdev,
5375 bdaddr_t *bdaddr, u8 type)
5376{
5377 struct mgmt_ev_device_removed ev;
5378
5379 bacpy(&ev.addr.bdaddr, bdaddr);
5380 ev.addr.type = type;
5381
5382 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5383}
5384
Marcel Holtmann2faade52014-06-29 19:44:03 +02005385static int remove_device(struct sock *sk, struct hci_dev *hdev,
5386 void *data, u16 len)
5387{
5388 struct mgmt_cp_remove_device *cp = data;
5389 int err;
5390
5391 BT_DBG("%s", hdev->name);
5392
5393 hci_dev_lock(hdev);
5394
5395 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005396 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005397 u8 addr_type;
5398
Johan Hedberg66593582014-07-09 12:59:14 +03005399 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005400 err = mgmt_cmd_complete(sk, hdev->id,
5401 MGMT_OP_REMOVE_DEVICE,
5402 MGMT_STATUS_INVALID_PARAMS,
5403 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005404 goto unlock;
5405 }
5406
Johan Hedberg66593582014-07-09 12:59:14 +03005407 if (cp->addr.type == BDADDR_BREDR) {
5408 err = hci_bdaddr_list_del(&hdev->whitelist,
5409 &cp->addr.bdaddr,
5410 cp->addr.type);
5411 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005412 err = mgmt_cmd_complete(sk, hdev->id,
5413 MGMT_OP_REMOVE_DEVICE,
5414 MGMT_STATUS_INVALID_PARAMS,
5415 &cp->addr,
5416 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005417 goto unlock;
5418 }
5419
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005420 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005421
Johan Hedberg66593582014-07-09 12:59:14 +03005422 device_removed(sk, hdev, &cp->addr.bdaddr,
5423 cp->addr.type);
5424 goto complete;
5425 }
5426
Johan Hedberg85813a72015-10-21 18:02:59 +03005427 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005428
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005429 /* Kernel internally uses conn_params with resolvable private
5430 * address, but Remove Device allows only identity addresses.
5431 * Make sure it is enforced before calling
5432 * hci_conn_params_lookup.
5433 */
5434 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005435 err = mgmt_cmd_complete(sk, hdev->id,
5436 MGMT_OP_REMOVE_DEVICE,
5437 MGMT_STATUS_INVALID_PARAMS,
5438 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005439 goto unlock;
5440 }
5441
Johan Hedbergc71593d2014-07-02 17:37:28 +03005442 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5443 addr_type);
5444 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005445 err = mgmt_cmd_complete(sk, hdev->id,
5446 MGMT_OP_REMOVE_DEVICE,
5447 MGMT_STATUS_INVALID_PARAMS,
5448 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005449 goto unlock;
5450 }
5451
Johan Hedberg679d2b62015-10-16 10:07:52 +03005452 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5453 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005454 err = mgmt_cmd_complete(sk, hdev->id,
5455 MGMT_OP_REMOVE_DEVICE,
5456 MGMT_STATUS_INVALID_PARAMS,
5457 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005458 goto unlock;
5459 }
5460
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005461 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005462 list_del(&params->list);
5463 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005464 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005465
5466 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005467 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005468 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005469 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005470
Marcel Holtmann2faade52014-06-29 19:44:03 +02005471 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005472 err = mgmt_cmd_complete(sk, hdev->id,
5473 MGMT_OP_REMOVE_DEVICE,
5474 MGMT_STATUS_INVALID_PARAMS,
5475 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005476 goto unlock;
5477 }
5478
Johan Hedberg66593582014-07-09 12:59:14 +03005479 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5480 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5481 list_del(&b->list);
5482 kfree(b);
5483 }
5484
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005485 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005486
Johan Hedberg19de0822014-07-06 13:06:51 +03005487 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5488 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5489 continue;
5490 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005491 if (p->explicit_connect) {
5492 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5493 continue;
5494 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005495 list_del(&p->action);
5496 list_del(&p->list);
5497 kfree(p);
5498 }
5499
5500 BT_DBG("All LE connection parameters were removed");
5501
Johan Hedberg51d7a942015-11-11 08:11:18 +02005502 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005503 }
5504
Johan Hedberg66593582014-07-09 12:59:14 +03005505complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005506 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5507 MGMT_STATUS_SUCCESS, &cp->addr,
5508 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005509unlock:
5510 hci_dev_unlock(hdev);
5511 return err;
5512}
5513
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005514static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5515 u16 len)
5516{
5517 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005518 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5519 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005520 u16 param_count, expected_len;
5521 int i;
5522
5523 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005524 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5525 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005526
5527 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005528 if (param_count > max_param_count) {
5529 BT_ERR("load_conn_param: too big param_count value %u",
5530 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005531 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5532 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005533 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005534
5535 expected_len = sizeof(*cp) + param_count *
5536 sizeof(struct mgmt_conn_param);
5537 if (expected_len != len) {
5538 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5539 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005540 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5541 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005542 }
5543
5544 BT_DBG("%s param_count %u", hdev->name, param_count);
5545
5546 hci_dev_lock(hdev);
5547
5548 hci_conn_params_clear_disabled(hdev);
5549
5550 for (i = 0; i < param_count; i++) {
5551 struct mgmt_conn_param *param = &cp->params[i];
5552 struct hci_conn_params *hci_param;
5553 u16 min, max, latency, timeout;
5554 u8 addr_type;
5555
5556 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5557 param->addr.type);
5558
5559 if (param->addr.type == BDADDR_LE_PUBLIC) {
5560 addr_type = ADDR_LE_DEV_PUBLIC;
5561 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5562 addr_type = ADDR_LE_DEV_RANDOM;
5563 } else {
5564 BT_ERR("Ignoring invalid connection parameters");
5565 continue;
5566 }
5567
5568 min = le16_to_cpu(param->min_interval);
5569 max = le16_to_cpu(param->max_interval);
5570 latency = le16_to_cpu(param->latency);
5571 timeout = le16_to_cpu(param->timeout);
5572
5573 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5574 min, max, latency, timeout);
5575
5576 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5577 BT_ERR("Ignoring invalid connection parameters");
5578 continue;
5579 }
5580
5581 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5582 addr_type);
5583 if (!hci_param) {
5584 BT_ERR("Failed to add connection parameters");
5585 continue;
5586 }
5587
5588 hci_param->conn_min_interval = min;
5589 hci_param->conn_max_interval = max;
5590 hci_param->conn_latency = latency;
5591 hci_param->supervision_timeout = timeout;
5592 }
5593
5594 hci_dev_unlock(hdev);
5595
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005596 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5597 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005598}
5599
Marcel Holtmanndbece372014-07-04 18:11:55 +02005600static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5601 void *data, u16 len)
5602{
5603 struct mgmt_cp_set_external_config *cp = data;
5604 bool changed;
5605 int err;
5606
5607 BT_DBG("%s", hdev->name);
5608
5609 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005610 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5611 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005612
5613 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005614 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5615 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005616
5617 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005618 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5619 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005620
5621 hci_dev_lock(hdev);
5622
5623 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005624 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005625 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005626 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005627
5628 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5629 if (err < 0)
5630 goto unlock;
5631
5632 if (!changed)
5633 goto unlock;
5634
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005635 err = new_options(hdev, sk);
5636
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005637 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005638 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005639
Marcel Holtmann516018a2015-03-13 02:11:04 -07005640 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005641 hci_dev_set_flag(hdev, HCI_CONFIG);
5642 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005643
5644 queue_work(hdev->req_workqueue, &hdev->power_on);
5645 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005646 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005647 mgmt_index_added(hdev);
5648 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005649 }
5650
5651unlock:
5652 hci_dev_unlock(hdev);
5653 return err;
5654}
5655
Marcel Holtmann9713c172014-07-06 12:11:15 +02005656static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5657 void *data, u16 len)
5658{
5659 struct mgmt_cp_set_public_address *cp = data;
5660 bool changed;
5661 int err;
5662
5663 BT_DBG("%s", hdev->name);
5664
5665 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005666 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5667 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005668
5669 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005670 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5671 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005672
5673 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5675 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005676
5677 hci_dev_lock(hdev);
5678
5679 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5680 bacpy(&hdev->public_addr, &cp->bdaddr);
5681
5682 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5683 if (err < 0)
5684 goto unlock;
5685
5686 if (!changed)
5687 goto unlock;
5688
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005689 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005690 err = new_options(hdev, sk);
5691
5692 if (is_configured(hdev)) {
5693 mgmt_index_removed(hdev);
5694
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005695 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005696
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005697 hci_dev_set_flag(hdev, HCI_CONFIG);
5698 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005699
5700 queue_work(hdev->req_workqueue, &hdev->power_on);
5701 }
5702
5703unlock:
5704 hci_dev_unlock(hdev);
5705 return err;
5706}
5707
Marcel Holtmannbea41602015-03-14 22:43:17 -07005708static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5709 u8 data_len)
5710{
5711 eir[eir_len++] = sizeof(type) + data_len;
5712 eir[eir_len++] = type;
5713 memcpy(&eir[eir_len], data, data_len);
5714 eir_len += data_len;
5715
5716 return eir_len;
5717}
5718
Johan Hedberg40f66c02015-04-07 21:52:22 +03005719static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5720 u16 opcode, struct sk_buff *skb)
5721{
5722 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5723 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5724 u8 *h192, *r192, *h256, *r256;
5725 struct mgmt_pending_cmd *cmd;
5726 u16 eir_len;
5727 int err;
5728
5729 BT_DBG("%s status %u", hdev->name, status);
5730
5731 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5732 if (!cmd)
5733 return;
5734
5735 mgmt_cp = cmd->param;
5736
5737 if (status) {
5738 status = mgmt_status(status);
5739 eir_len = 0;
5740
5741 h192 = NULL;
5742 r192 = NULL;
5743 h256 = NULL;
5744 r256 = NULL;
5745 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5746 struct hci_rp_read_local_oob_data *rp;
5747
5748 if (skb->len != sizeof(*rp)) {
5749 status = MGMT_STATUS_FAILED;
5750 eir_len = 0;
5751 } else {
5752 status = MGMT_STATUS_SUCCESS;
5753 rp = (void *)skb->data;
5754
5755 eir_len = 5 + 18 + 18;
5756 h192 = rp->hash;
5757 r192 = rp->rand;
5758 h256 = NULL;
5759 r256 = NULL;
5760 }
5761 } else {
5762 struct hci_rp_read_local_oob_ext_data *rp;
5763
5764 if (skb->len != sizeof(*rp)) {
5765 status = MGMT_STATUS_FAILED;
5766 eir_len = 0;
5767 } else {
5768 status = MGMT_STATUS_SUCCESS;
5769 rp = (void *)skb->data;
5770
5771 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5772 eir_len = 5 + 18 + 18;
5773 h192 = NULL;
5774 r192 = NULL;
5775 } else {
5776 eir_len = 5 + 18 + 18 + 18 + 18;
5777 h192 = rp->hash192;
5778 r192 = rp->rand192;
5779 }
5780
5781 h256 = rp->hash256;
5782 r256 = rp->rand256;
5783 }
5784 }
5785
5786 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5787 if (!mgmt_rp)
5788 goto done;
5789
5790 if (status)
5791 goto send_rsp;
5792
5793 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5794 hdev->dev_class, 3);
5795
5796 if (h192 && r192) {
5797 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5798 EIR_SSP_HASH_C192, h192, 16);
5799 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5800 EIR_SSP_RAND_R192, r192, 16);
5801 }
5802
5803 if (h256 && r256) {
5804 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5805 EIR_SSP_HASH_C256, h256, 16);
5806 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5807 EIR_SSP_RAND_R256, r256, 16);
5808 }
5809
5810send_rsp:
5811 mgmt_rp->type = mgmt_cp->type;
5812 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5813
5814 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5815 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5816 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5817 if (err < 0 || status)
5818 goto done;
5819
5820 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5821
5822 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5823 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5824 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5825done:
5826 kfree(mgmt_rp);
5827 mgmt_pending_remove(cmd);
5828}
5829
5830static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5831 struct mgmt_cp_read_local_oob_ext_data *cp)
5832{
5833 struct mgmt_pending_cmd *cmd;
5834 struct hci_request req;
5835 int err;
5836
5837 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5838 cp, sizeof(*cp));
5839 if (!cmd)
5840 return -ENOMEM;
5841
5842 hci_req_init(&req, hdev);
5843
5844 if (bredr_sc_enabled(hdev))
5845 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5846 else
5847 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5848
5849 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5850 if (err < 0) {
5851 mgmt_pending_remove(cmd);
5852 return err;
5853 }
5854
5855 return 0;
5856}
5857
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005858static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5859 void *data, u16 data_len)
5860{
5861 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5862 struct mgmt_rp_read_local_oob_ext_data *rp;
5863 size_t rp_len;
5864 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005865 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005866 int err;
5867
5868 BT_DBG("%s", hdev->name);
5869
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005870 if (hdev_is_powered(hdev)) {
5871 switch (cp->type) {
5872 case BIT(BDADDR_BREDR):
5873 status = mgmt_bredr_support(hdev);
5874 if (status)
5875 eir_len = 0;
5876 else
5877 eir_len = 5;
5878 break;
5879 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5880 status = mgmt_le_support(hdev);
5881 if (status)
5882 eir_len = 0;
5883 else
5884 eir_len = 9 + 3 + 18 + 18 + 3;
5885 break;
5886 default:
5887 status = MGMT_STATUS_INVALID_PARAMS;
5888 eir_len = 0;
5889 break;
5890 }
5891 } else {
5892 status = MGMT_STATUS_NOT_POWERED;
5893 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005894 }
5895
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005896 rp_len = sizeof(*rp) + eir_len;
5897 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005898 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005899 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005900
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005901 if (status)
5902 goto complete;
5903
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005904 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005905
5906 eir_len = 0;
5907 switch (cp->type) {
5908 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005909 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5910 err = read_local_ssp_oob_req(hdev, sk, cp);
5911 hci_dev_unlock(hdev);
5912 if (!err)
5913 goto done;
5914
5915 status = MGMT_STATUS_FAILED;
5916 goto complete;
5917 } else {
5918 eir_len = eir_append_data(rp->eir, eir_len,
5919 EIR_CLASS_OF_DEV,
5920 hdev->dev_class, 3);
5921 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005922 break;
5923 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005924 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5925 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005926 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005927 status = MGMT_STATUS_FAILED;
5928 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005929 }
5930
Marcel Holtmanne2135682015-04-02 12:00:58 -07005931 /* This should return the active RPA, but since the RPA
5932 * is only programmed on demand, it is really hard to fill
5933 * this in at the moment. For now disallow retrieving
5934 * local out-of-band data when privacy is in use.
5935 *
5936 * Returning the identity address will not help here since
5937 * pairing happens before the identity resolving key is
5938 * known and thus the connection establishment happens
5939 * based on the RPA and not the identity address.
5940 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005941 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005942 hci_dev_unlock(hdev);
5943 status = MGMT_STATUS_REJECTED;
5944 goto complete;
5945 }
5946
5947 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5948 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5949 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5950 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005951 memcpy(addr, &hdev->static_addr, 6);
5952 addr[6] = 0x01;
5953 } else {
5954 memcpy(addr, &hdev->bdaddr, 6);
5955 addr[6] = 0x00;
5956 }
5957
5958 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5959 addr, sizeof(addr));
5960
5961 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5962 role = 0x02;
5963 else
5964 role = 0x01;
5965
5966 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5967 &role, sizeof(role));
5968
Marcel Holtmann5082a592015-03-16 12:39:00 -07005969 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5970 eir_len = eir_append_data(rp->eir, eir_len,
5971 EIR_LE_SC_CONFIRM,
5972 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005973
Marcel Holtmann5082a592015-03-16 12:39:00 -07005974 eir_len = eir_append_data(rp->eir, eir_len,
5975 EIR_LE_SC_RANDOM,
5976 rand, sizeof(rand));
5977 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005978
Johan Hedbergf2252572015-11-18 12:49:20 +02005979 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005980
5981 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5982 flags |= LE_AD_NO_BREDR;
5983
5984 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5985 &flags, sizeof(flags));
5986 break;
5987 }
5988
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005989 hci_dev_unlock(hdev);
5990
Marcel Holtmann72000df2015-03-16 16:11:21 -07005991 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5992
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005993 status = MGMT_STATUS_SUCCESS;
5994
5995complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005996 rp->type = cp->type;
5997 rp->eir_len = cpu_to_le16(eir_len);
5998
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005999 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006000 status, rp, sizeof(*rp) + eir_len);
6001 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006002 goto done;
6003
6004 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6005 rp, sizeof(*rp) + eir_len,
6006 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006007
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006008done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006009 kfree(rp);
6010
6011 return err;
6012}
6013
Arman Uguray089fa8c2015-03-25 18:53:45 -07006014static u32 get_supported_adv_flags(struct hci_dev *hdev)
6015{
6016 u32 flags = 0;
6017
6018 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6019 flags |= MGMT_ADV_FLAG_DISCOV;
6020 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6021 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
6022
6023 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
6024 flags |= MGMT_ADV_FLAG_TX_POWER;
6025
6026 return flags;
6027}
6028
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006029static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6030 void *data, u16 data_len)
6031{
6032 struct mgmt_rp_read_adv_features *rp;
6033 size_t rp_len;
Florian Grandel286e0c82015-06-18 03:16:38 +02006034 int err, i;
Arman Uguray24b4f382015-03-23 15:57:12 -07006035 bool instance;
Florian Grandel286e0c82015-06-18 03:16:38 +02006036 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006037 u32 supported_flags;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006038
6039 BT_DBG("%s", hdev->name);
6040
Arman Uguray089fa8c2015-03-25 18:53:45 -07006041 if (!lmp_le_capable(hdev))
6042 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6043 MGMT_STATUS_REJECTED);
6044
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006045 hci_dev_lock(hdev);
6046
6047 rp_len = sizeof(*rp);
Arman Uguray24b4f382015-03-23 15:57:12 -07006048
Arman Uguray24b4f382015-03-23 15:57:12 -07006049 instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
6050 if (instance)
Florian Grandel286e0c82015-06-18 03:16:38 +02006051 rp_len += hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006052
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006053 rp = kmalloc(rp_len, GFP_ATOMIC);
6054 if (!rp) {
6055 hci_dev_unlock(hdev);
6056 return -ENOMEM;
6057 }
6058
Arman Uguray089fa8c2015-03-25 18:53:45 -07006059 supported_flags = get_supported_adv_flags(hdev);
6060
6061 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006062 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6063 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006064 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Arman Uguray24b4f382015-03-23 15:57:12 -07006065
Arman Uguray24b4f382015-03-23 15:57:12 -07006066 if (instance) {
Florian Grandel286e0c82015-06-18 03:16:38 +02006067 i = 0;
6068 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6069 if (i >= hdev->adv_instance_cnt)
6070 break;
6071
6072 rp->instance[i] = adv_instance->instance;
6073 i++;
6074 }
6075 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006076 } else {
6077 rp->num_instances = 0;
6078 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006079
6080 hci_dev_unlock(hdev);
6081
6082 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6083 MGMT_STATUS_SUCCESS, rp, rp_len);
6084
6085 kfree(rp);
6086
6087 return err;
6088}
6089
Arman Uguray4117ed72015-03-23 15:57:14 -07006090static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006091 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006092{
Arman Uguray4117ed72015-03-23 15:57:14 -07006093 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006094 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07006095 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07006096 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07006097
Marcel Holtmann31a32482015-11-19 16:16:42 +01006098 if (is_adv_data) {
6099 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6100 MGMT_ADV_FLAG_LIMITED_DISCOV |
6101 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
6102 flags_managed = true;
6103 max_len -= 3;
6104 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006105
Marcel Holtmann31a32482015-11-19 16:16:42 +01006106 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
6107 tx_power_managed = true;
6108 max_len -= 3;
6109 }
Arman Uguray5507e352015-03-25 18:53:44 -07006110 }
6111
Arman Uguray4117ed72015-03-23 15:57:14 -07006112 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006113 return false;
6114
Arman Uguray4117ed72015-03-23 15:57:14 -07006115 /* Make sure that the data is correctly formatted. */
6116 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6117 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006118
Arman Ugurayb44133f2015-03-25 18:53:41 -07006119 if (flags_managed && data[i + 1] == EIR_FLAGS)
6120 return false;
6121
Arman Uguray5507e352015-03-25 18:53:44 -07006122 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
6123 return false;
6124
Arman Uguray24b4f382015-03-23 15:57:12 -07006125 /* If the current field length would exceed the total data
6126 * length, then it's invalid.
6127 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006128 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006129 return false;
6130 }
6131
6132 return true;
6133}
6134
Arman Uguray24b4f382015-03-23 15:57:12 -07006135static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6136 u16 opcode)
6137{
6138 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006139 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006140 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006141 struct adv_info *adv_instance, *n;
6142 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006143
6144 BT_DBG("status %d", status);
6145
6146 hci_dev_lock(hdev);
6147
6148 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6149
Florian Grandelfffd38b2015-06-18 03:16:47 +02006150 if (status)
Arman Uguray24b4f382015-03-23 15:57:12 -07006151 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006152
6153 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6154 if (!adv_instance->pending)
6155 continue;
6156
6157 if (!status) {
6158 adv_instance->pending = false;
6159 continue;
6160 }
6161
6162 instance = adv_instance->instance;
6163
6164 if (hdev->cur_adv_instance == instance)
6165 cancel_adv_timeout(hdev);
6166
6167 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006168 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006169 }
6170
6171 if (!cmd)
6172 goto unlock;
6173
Florian Grandelfffd38b2015-06-18 03:16:47 +02006174 cp = cmd->param;
6175 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006176
6177 if (status)
6178 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6179 mgmt_status(status));
6180 else
6181 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6182 mgmt_status(status), &rp, sizeof(rp));
6183
6184 mgmt_pending_remove(cmd);
6185
6186unlock:
6187 hci_dev_unlock(hdev);
6188}
6189
6190static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6191 void *data, u16 data_len)
6192{
6193 struct mgmt_cp_add_advertising *cp = data;
6194 struct mgmt_rp_add_advertising rp;
6195 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006196 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006197 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006198 u16 timeout, duration;
6199 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6200 u8 schedule_instance = 0;
6201 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006202 int err;
6203 struct mgmt_pending_cmd *cmd;
6204 struct hci_request req;
6205
6206 BT_DBG("%s", hdev->name);
6207
6208 status = mgmt_le_support(hdev);
6209 if (status)
6210 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6211 status);
6212
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006213 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6214 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6215 MGMT_STATUS_INVALID_PARAMS);
6216
Arman Uguray24b4f382015-03-23 15:57:12 -07006217 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006218 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006219 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006220
Florian Grandelfffd38b2015-06-18 03:16:47 +02006221 /* The current implementation only supports a subset of the specified
6222 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006223 */
6224 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006225 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006226 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6227 MGMT_STATUS_INVALID_PARAMS);
6228
6229 hci_dev_lock(hdev);
6230
Arman Uguray912098a2015-03-23 15:57:15 -07006231 if (timeout && !hdev_is_powered(hdev)) {
6232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6233 MGMT_STATUS_REJECTED);
6234 goto unlock;
6235 }
6236
Arman Uguray24b4f382015-03-23 15:57:12 -07006237 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006238 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006239 pending_find(MGMT_OP_SET_LE, hdev)) {
6240 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6241 MGMT_STATUS_BUSY);
6242 goto unlock;
6243 }
6244
Arman Ugurayb44133f2015-03-25 18:53:41 -07006245 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006246 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006247 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006248 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6249 MGMT_STATUS_INVALID_PARAMS);
6250 goto unlock;
6251 }
6252
Florian Grandelfffd38b2015-06-18 03:16:47 +02006253 err = hci_add_adv_instance(hdev, cp->instance, flags,
6254 cp->adv_data_len, cp->data,
6255 cp->scan_rsp_len,
6256 cp->data + cp->adv_data_len,
6257 timeout, duration);
6258 if (err < 0) {
6259 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6260 MGMT_STATUS_FAILED);
6261 goto unlock;
6262 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006263
Florian Grandelfffd38b2015-06-18 03:16:47 +02006264 /* Only trigger an advertising added event if a new instance was
6265 * actually added.
6266 */
6267 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006268 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006269
Florian Grandelfffd38b2015-06-18 03:16:47 +02006270 hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
Arman Uguray24b4f382015-03-23 15:57:12 -07006271
Florian Grandelfffd38b2015-06-18 03:16:47 +02006272 if (hdev->cur_adv_instance == cp->instance) {
6273 /* If the currently advertised instance is being changed then
6274 * cancel the current advertising and schedule the next
6275 * instance. If there is only one instance then the overridden
6276 * advertising data will be visible right away.
6277 */
6278 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006279
Florian Grandelfffd38b2015-06-18 03:16:47 +02006280 next_instance = hci_get_next_instance(hdev, cp->instance);
6281 if (next_instance)
6282 schedule_instance = next_instance->instance;
6283 } else if (!hdev->adv_instance_timeout) {
6284 /* Immediately advertise the new instance if no other
6285 * instance is currently being advertised.
6286 */
6287 schedule_instance = cp->instance;
6288 }
Arman Uguray912098a2015-03-23 15:57:15 -07006289
Florian Grandelfffd38b2015-06-18 03:16:47 +02006290 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6291 * there is no instance to be advertised then we have no HCI
6292 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006293 */
6294 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006295 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6296 !schedule_instance) {
6297 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006298 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6299 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6300 goto unlock;
6301 }
6302
6303 /* We're good to go, update advertising data, parameters, and start
6304 * advertising.
6305 */
6306 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6307 data_len);
6308 if (!cmd) {
6309 err = -ENOMEM;
6310 goto unlock;
6311 }
6312
6313 hci_req_init(&req, hdev);
6314
Johan Hedbergf2252572015-11-18 12:49:20 +02006315 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006316
Florian Grandelfffd38b2015-06-18 03:16:47 +02006317 if (!err)
6318 err = hci_req_run(&req, add_advertising_complete);
6319
Arman Uguray24b4f382015-03-23 15:57:12 -07006320 if (err < 0)
6321 mgmt_pending_remove(cmd);
6322
6323unlock:
6324 hci_dev_unlock(hdev);
6325
6326 return err;
6327}
6328
Arman Ugurayda9293352015-03-23 15:57:13 -07006329static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6330 u16 opcode)
6331{
6332 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006333 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006334 struct mgmt_rp_remove_advertising rp;
6335
6336 BT_DBG("status %d", status);
6337
6338 hci_dev_lock(hdev);
6339
6340 /* A failure status here only means that we failed to disable
6341 * advertising. Otherwise, the advertising instance has been removed,
6342 * so report success.
6343 */
6344 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6345 if (!cmd)
6346 goto unlock;
6347
Florian Grandel01948332015-06-18 03:16:48 +02006348 cp = cmd->param;
6349 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006350
6351 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6352 &rp, sizeof(rp));
6353 mgmt_pending_remove(cmd);
6354
6355unlock:
6356 hci_dev_unlock(hdev);
6357}
6358
6359static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6360 void *data, u16 data_len)
6361{
6362 struct mgmt_cp_remove_advertising *cp = data;
6363 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006364 struct mgmt_pending_cmd *cmd;
6365 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006366 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006367
6368 BT_DBG("%s", hdev->name);
6369
Arman Ugurayda9293352015-03-23 15:57:13 -07006370 hci_dev_lock(hdev);
6371
Johan Hedberg952497b2015-06-18 21:05:31 +03006372 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006373 err = mgmt_cmd_status(sk, hdev->id,
6374 MGMT_OP_REMOVE_ADVERTISING,
6375 MGMT_STATUS_INVALID_PARAMS);
6376 goto unlock;
6377 }
6378
Arman Ugurayda9293352015-03-23 15:57:13 -07006379 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6380 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6381 pending_find(MGMT_OP_SET_LE, hdev)) {
6382 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6383 MGMT_STATUS_BUSY);
6384 goto unlock;
6385 }
6386
6387 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
6388 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6389 MGMT_STATUS_INVALID_PARAMS);
6390 goto unlock;
6391 }
6392
Florian Grandel01948332015-06-18 03:16:48 +02006393 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006394
Johan Hedbergf2252572015-11-18 12:49:20 +02006395 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006396
Florian Grandel01948332015-06-18 03:16:48 +02006397 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006398 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006399
Florian Grandel01948332015-06-18 03:16:48 +02006400 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6401 * flag is set or the device isn't powered then we have no HCI
6402 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006403 */
Florian Grandel01948332015-06-18 03:16:48 +02006404 if (skb_queue_empty(&req.cmd_q) ||
6405 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006406 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006407 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006408 err = mgmt_cmd_complete(sk, hdev->id,
6409 MGMT_OP_REMOVE_ADVERTISING,
6410 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6411 goto unlock;
6412 }
6413
6414 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6415 data_len);
6416 if (!cmd) {
6417 err = -ENOMEM;
6418 goto unlock;
6419 }
6420
Arman Ugurayda9293352015-03-23 15:57:13 -07006421 err = hci_req_run(&req, remove_advertising_complete);
6422 if (err < 0)
6423 mgmt_pending_remove(cmd);
6424
6425unlock:
6426 hci_dev_unlock(hdev);
6427
6428 return err;
6429}
6430
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006431static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6432{
6433 u8 max_len = HCI_MAX_AD_LENGTH;
6434
6435 if (is_adv_data) {
6436 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6437 MGMT_ADV_FLAG_LIMITED_DISCOV |
6438 MGMT_ADV_FLAG_MANAGED_FLAGS))
6439 max_len -= 3;
6440
6441 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6442 max_len -= 3;
6443 }
6444
6445 return max_len;
6446}
6447
6448static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6449 void *data, u16 data_len)
6450{
6451 struct mgmt_cp_get_adv_size_info *cp = data;
6452 struct mgmt_rp_get_adv_size_info rp;
6453 u32 flags, supported_flags;
6454 int err;
6455
6456 BT_DBG("%s", hdev->name);
6457
6458 if (!lmp_le_capable(hdev))
6459 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6460 MGMT_STATUS_REJECTED);
6461
6462 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6463 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6464 MGMT_STATUS_INVALID_PARAMS);
6465
6466 flags = __le32_to_cpu(cp->flags);
6467
6468 /* The current implementation only supports a subset of the specified
6469 * flags.
6470 */
6471 supported_flags = get_supported_adv_flags(hdev);
6472 if (flags & ~supported_flags)
6473 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6474 MGMT_STATUS_INVALID_PARAMS);
6475
6476 rp.instance = cp->instance;
6477 rp.flags = cp->flags;
6478 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6479 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6480
6481 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6482 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6483
6484 return err;
6485}
6486
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006487static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006488 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006489 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006490 HCI_MGMT_NO_HDEV |
6491 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006492 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006493 HCI_MGMT_NO_HDEV |
6494 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006495 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006496 HCI_MGMT_NO_HDEV |
6497 HCI_MGMT_UNTRUSTED },
6498 { read_controller_info, MGMT_READ_INFO_SIZE,
6499 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006500 { set_powered, MGMT_SETTING_SIZE },
6501 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6502 { set_connectable, MGMT_SETTING_SIZE },
6503 { set_fast_connectable, MGMT_SETTING_SIZE },
6504 { set_bondable, MGMT_SETTING_SIZE },
6505 { set_link_security, MGMT_SETTING_SIZE },
6506 { set_ssp, MGMT_SETTING_SIZE },
6507 { set_hs, MGMT_SETTING_SIZE },
6508 { set_le, MGMT_SETTING_SIZE },
6509 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6510 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6511 { add_uuid, MGMT_ADD_UUID_SIZE },
6512 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006513 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6514 HCI_MGMT_VAR_LEN },
6515 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6516 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006517 { disconnect, MGMT_DISCONNECT_SIZE },
6518 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6519 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6520 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6521 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6522 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6523 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6524 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6525 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6526 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6527 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6528 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006529 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6530 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6531 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006532 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6533 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6534 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6535 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6536 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6537 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6538 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6539 { set_advertising, MGMT_SETTING_SIZE },
6540 { set_bredr, MGMT_SETTING_SIZE },
6541 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6542 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6543 { set_secure_conn, MGMT_SETTING_SIZE },
6544 { set_debug_keys, MGMT_SETTING_SIZE },
6545 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006546 { load_irks, MGMT_LOAD_IRKS_SIZE,
6547 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006548 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6549 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6550 { add_device, MGMT_ADD_DEVICE_SIZE },
6551 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006552 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6553 HCI_MGMT_VAR_LEN },
6554 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006555 HCI_MGMT_NO_HDEV |
6556 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006557 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006558 HCI_MGMT_UNCONFIGURED |
6559 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006560 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6561 HCI_MGMT_UNCONFIGURED },
6562 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6563 HCI_MGMT_UNCONFIGURED },
6564 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6565 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006566 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006567 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006568 HCI_MGMT_NO_HDEV |
6569 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006570 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006571 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6572 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006573 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006574 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006575};
6576
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006577void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006578{
Marcel Holtmannced85542015-03-14 19:27:56 -07006579 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006580
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006581 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6582 return;
6583
Marcel Holtmannf9207332015-03-14 19:27:55 -07006584 switch (hdev->dev_type) {
6585 case HCI_BREDR:
6586 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6587 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6588 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006589 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006590 } else {
6591 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6592 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006593 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006594 }
6595 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006596 case HCI_AMP:
6597 ev.type = 0x02;
6598 break;
6599 default:
6600 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006601 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006602
6603 ev.bus = hdev->bus;
6604
6605 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6606 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006607}
6608
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006609void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006610{
Marcel Holtmannced85542015-03-14 19:27:56 -07006611 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006612 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006613
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006614 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6615 return;
6616
Marcel Holtmannf9207332015-03-14 19:27:55 -07006617 switch (hdev->dev_type) {
6618 case HCI_BREDR:
6619 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006620
Marcel Holtmannf9207332015-03-14 19:27:55 -07006621 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6622 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6623 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006624 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006625 } else {
6626 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6627 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006628 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006629 }
6630 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006631 case HCI_AMP:
6632 ev.type = 0x02;
6633 break;
6634 default:
6635 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006636 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006637
6638 ev.bus = hdev->bus;
6639
6640 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6641 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006642}
6643
Andre Guedes6046dc32014-02-26 20:21:51 -03006644/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006645static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006646{
6647 struct hci_conn_params *p;
6648
6649 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006650 /* Needed for AUTO_OFF case where might not "really"
6651 * have been powered off.
6652 */
6653 list_del_init(&p->action);
6654
6655 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006656 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006657 case HCI_AUTO_CONN_ALWAYS:
6658 list_add(&p->action, &hdev->pend_le_conns);
6659 break;
6660 case HCI_AUTO_CONN_REPORT:
6661 list_add(&p->action, &hdev->pend_le_reports);
6662 break;
6663 default:
6664 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006665 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006666 }
6667}
6668
Marcel Holtmann1904a852015-01-11 13:50:44 -08006669static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006670{
6671 struct cmd_lookup match = { NULL, hdev };
6672
6673 BT_DBG("status 0x%02x", status);
6674
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006675 if (!status) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006676 restart_le_actions(hdev);
6677 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006678 }
6679
Johan Hedberg229ab392013-03-15 17:06:53 -05006680 hci_dev_lock(hdev);
6681
6682 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6683
6684 new_settings(hdev, match.sk);
6685
6686 hci_dev_unlock(hdev);
6687
6688 if (match.sk)
6689 sock_put(match.sk);
6690}
6691
Johan Hedberg70da6242013-03-15 17:06:51 -05006692static int powered_update_hci(struct hci_dev *hdev)
6693{
Johan Hedberg890ea892013-03-15 17:06:52 -05006694 struct hci_request req;
Florian Grandel320b3bf2015-06-18 03:16:49 +02006695 struct adv_info *adv_instance;
Johan Hedberg70da6242013-03-15 17:06:51 -05006696 u8 link_sec;
6697
Johan Hedberg890ea892013-03-15 17:06:52 -05006698 hci_req_init(&req, hdev);
6699
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006700 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006701 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006702 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006703
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006704 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006705
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006706 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6707 u8 support = 0x01;
6708
6709 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6710 sizeof(support), &support);
6711 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006712 }
6713
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006714 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006715 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006716 struct hci_cp_write_le_host_supported cp;
6717
Marcel Holtmann32226e42014-07-24 20:04:16 +02006718 cp.le = 0x01;
6719 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006720
6721 /* Check first if we already have the right
6722 * host state (host features set)
6723 */
6724 if (cp.le != lmp_host_le_capable(hdev) ||
6725 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006726 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6727 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006728 }
6729
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006730 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006731 /* Make sure the controller has a good default for
6732 * advertising data. This also applies to the case
6733 * where BR/EDR was toggled during the AUTO_OFF phase.
6734 */
Florian Grandel320b3bf2015-06-18 03:16:49 +02006735 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
6736 (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6737 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
Johan Hedbergf2252572015-11-18 12:49:20 +02006738 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
6739 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006740 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006741
Florian Grandel320b3bf2015-06-18 03:16:49 +02006742 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6743 hdev->cur_adv_instance == 0x00 &&
6744 !list_empty(&hdev->adv_instances)) {
6745 adv_instance = list_first_entry(&hdev->adv_instances,
6746 struct adv_info, list);
6747 hdev->cur_adv_instance = adv_instance->instance;
6748 }
6749
6750 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergf2252572015-11-18 12:49:20 +02006751 __hci_req_enable_advertising(&req);
Florian Grandel320b3bf2015-06-18 03:16:49 +02006752 else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6753 hdev->cur_adv_instance)
Johan Hedbergf2252572015-11-18 12:49:20 +02006754 __hci_req_schedule_adv_instance(&req,
6755 hdev->cur_adv_instance,
6756 true);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006757 }
6758
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006759 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006760 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006761 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6762 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006763
6764 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006765 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006766 write_fast_connectable(&req, true);
6767 else
6768 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006769 __hci_req_update_scan(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02006770 __hci_req_update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006771 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006772 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006773 }
6774
Johan Hedberg229ab392013-03-15 17:06:53 -05006775 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006776}
6777
Johan Hedberg744cf192011-11-08 20:40:14 +02006778int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006779{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006780 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006781 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006782 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006783
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006784 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006785 return 0;
6786
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006787 if (powered) {
Andrzej Kaczmareke59a5542015-11-22 21:42:21 +01006788 /* Register the available SMP channels (BR/EDR and LE) only
6789 * when successfully powering on the controller. This late
6790 * registration is required so that LE SMP can clearly
6791 * decide if the public address or static address is used.
6792 */
6793 smp_register(hdev);
6794
Johan Hedberg229ab392013-03-15 17:06:53 -05006795 if (powered_update_hci(hdev) == 0)
6796 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006797
Johan Hedberg229ab392013-03-15 17:06:53 -05006798 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6799 &match);
6800 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006801 }
6802
Johan Hedberg229ab392013-03-15 17:06:53 -05006803 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006804
6805 /* If the power off is because of hdev unregistration let
6806 * use the appropriate INVALID_INDEX status. Otherwise use
6807 * NOT_POWERED. We cover both scenarios here since later in
6808 * mgmt_index_removed() any hci_conn callbacks will have already
6809 * been triggered, potentially causing misleading DISCONNECTED
6810 * status responses.
6811 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006812 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006813 status = MGMT_STATUS_INVALID_INDEX;
6814 else
6815 status = MGMT_STATUS_NOT_POWERED;
6816
6817 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006818
6819 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006820 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6821 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006822
6823new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006824 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006825
6826 if (match.sk)
6827 sock_put(match.sk);
6828
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006829 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006830}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006831
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006832void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006833{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006834 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006835 u8 status;
6836
Johan Hedberg333ae952015-03-17 13:48:47 +02006837 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006838 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006839 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006840
6841 if (err == -ERFKILL)
6842 status = MGMT_STATUS_RFKILLED;
6843 else
6844 status = MGMT_STATUS_FAILED;
6845
Johan Hedberga69e8372015-03-06 21:08:53 +02006846 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006847
6848 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006849}
6850
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006851void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6852 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006853{
Johan Hedberg86742e12011-11-07 23:13:38 +02006854 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006855
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006856 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006857
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006858 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006859 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006860 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006861 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006862 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006863 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006864
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006865 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006866}
Johan Hedbergf7520542011-01-20 12:34:39 +02006867
Johan Hedbergd7b25452014-05-23 13:19:53 +03006868static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6869{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006870 switch (ltk->type) {
6871 case SMP_LTK:
6872 case SMP_LTK_SLAVE:
6873 if (ltk->authenticated)
6874 return MGMT_LTK_AUTHENTICATED;
6875 return MGMT_LTK_UNAUTHENTICATED;
6876 case SMP_LTK_P256:
6877 if (ltk->authenticated)
6878 return MGMT_LTK_P256_AUTH;
6879 return MGMT_LTK_P256_UNAUTH;
6880 case SMP_LTK_P256_DEBUG:
6881 return MGMT_LTK_P256_DEBUG;
6882 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006883
6884 return MGMT_LTK_UNAUTHENTICATED;
6885}
6886
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006887void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006888{
6889 struct mgmt_ev_new_long_term_key ev;
6890
6891 memset(&ev, 0, sizeof(ev));
6892
Marcel Holtmann5192d302014-02-19 17:11:58 -08006893 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006894 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006895 * to store long term keys. Their addresses will change the
6896 * next time around.
6897 *
6898 * Only when a remote device provides an identity address
6899 * make sure the long term key is stored. If the remote
6900 * identity is known, the long term keys are internally
6901 * mapped to the identity address. So allow static random
6902 * and public addresses here.
6903 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006904 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6905 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6906 ev.store_hint = 0x00;
6907 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006908 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006909
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006910 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006911 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006912 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006913 ev.key.enc_size = key->enc_size;
6914 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006915 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006916
Johan Hedberg2ceba532014-06-16 19:25:16 +03006917 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006918 ev.key.master = 1;
6919
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006920 /* Make sure we copy only the significant bytes based on the
6921 * encryption key size, and set the rest of the value to zeroes.
6922 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006923 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006924 memset(ev.key.val + key->enc_size, 0,
6925 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006926
Marcel Holtmann083368f2013-10-15 14:26:29 -07006927 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006928}
6929
Johan Hedbergcad20c22015-10-12 13:36:19 +02006930void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006931{
6932 struct mgmt_ev_new_irk ev;
6933
6934 memset(&ev, 0, sizeof(ev));
6935
Johan Hedbergcad20c22015-10-12 13:36:19 +02006936 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006937
Johan Hedberg95fbac82014-02-19 15:18:31 +02006938 bacpy(&ev.rpa, &irk->rpa);
6939 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6940 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6941 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6942
6943 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6944}
6945
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006946void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6947 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006948{
6949 struct mgmt_ev_new_csrk ev;
6950
6951 memset(&ev, 0, sizeof(ev));
6952
6953 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006954 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006955 * to store signature resolving keys. Their addresses will change
6956 * the next time around.
6957 *
6958 * Only when a remote device provides an identity address
6959 * make sure the signature resolving key is stored. So allow
6960 * static random and public addresses here.
6961 */
6962 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6963 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6964 ev.store_hint = 0x00;
6965 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006966 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006967
6968 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6969 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006970 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006971 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6972
6973 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6974}
6975
Andre Guedesffb5a8272014-07-01 18:10:11 -03006976void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006977 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6978 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006979{
6980 struct mgmt_ev_new_conn_param ev;
6981
Johan Hedbergc103aea2014-07-02 17:37:34 +03006982 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6983 return;
6984
Andre Guedesffb5a8272014-07-01 18:10:11 -03006985 memset(&ev, 0, sizeof(ev));
6986 bacpy(&ev.addr.bdaddr, bdaddr);
6987 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006988 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006989 ev.min_interval = cpu_to_le16(min_interval);
6990 ev.max_interval = cpu_to_le16(max_interval);
6991 ev.latency = cpu_to_le16(latency);
6992 ev.timeout = cpu_to_le16(timeout);
6993
6994 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6995}
6996
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006997void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6998 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006999{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007000 char buf[512];
7001 struct mgmt_ev_device_connected *ev = (void *) buf;
7002 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007003
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007004 bacpy(&ev->addr.bdaddr, &conn->dst);
7005 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007006
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007007 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007008
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007009 /* We must ensure that the EIR Data fields are ordered and
7010 * unique. Keep it simple for now and avoid the problem by not
7011 * adding any BR/EDR data to the LE adv.
7012 */
7013 if (conn->le_adv_data_len > 0) {
7014 memcpy(&ev->eir[eir_len],
7015 conn->le_adv_data, conn->le_adv_data_len);
7016 eir_len = conn->le_adv_data_len;
7017 } else {
7018 if (name_len > 0)
7019 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7020 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007021
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007022 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007023 eir_len = eir_append_data(ev->eir, eir_len,
7024 EIR_CLASS_OF_DEV,
7025 conn->dev_class, 3);
7026 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007027
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007028 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007029
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007030 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7031 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007032}
7033
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007034static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007035{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007036 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007037
Johan Hedbergf5818c22014-12-05 13:36:02 +02007038 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007039
7040 *sk = cmd->sk;
7041 sock_hold(*sk);
7042
Johan Hedberga664b5b2011-02-19 12:06:02 -03007043 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007044}
7045
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007046static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007047{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007048 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007049 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007050
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007051 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7052
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007053 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007054 mgmt_pending_remove(cmd);
7055}
7056
Johan Hedberg84c61d92014-08-01 11:13:30 +03007057bool mgmt_powering_down(struct hci_dev *hdev)
7058{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007059 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007060 struct mgmt_mode *cp;
7061
Johan Hedberg333ae952015-03-17 13:48:47 +02007062 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007063 if (!cmd)
7064 return false;
7065
7066 cp = cmd->param;
7067 if (!cp->val)
7068 return true;
7069
7070 return false;
7071}
7072
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007073void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007074 u8 link_type, u8 addr_type, u8 reason,
7075 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007076{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007077 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007078 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007079
Johan Hedberg84c61d92014-08-01 11:13:30 +03007080 /* The connection is still in hci_conn_hash so test for 1
7081 * instead of 0 to know if this is the last one.
7082 */
7083 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7084 cancel_delayed_work(&hdev->power_off);
7085 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007086 }
7087
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007088 if (!mgmt_connected)
7089 return;
7090
Andre Guedes57eb7762013-10-30 19:01:41 -03007091 if (link_type != ACL_LINK && link_type != LE_LINK)
7092 return;
7093
Johan Hedberg744cf192011-11-08 20:40:14 +02007094 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007095
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007096 bacpy(&ev.addr.bdaddr, bdaddr);
7097 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7098 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007099
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007100 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007101
7102 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007103 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007104
Johan Hedberg124f6e32012-02-09 13:50:12 +02007105 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007106 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007107}
7108
Marcel Holtmann78929242013-10-06 23:55:47 -07007109void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7110 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007111{
Andre Guedes3655bba2013-10-30 19:01:40 -03007112 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7113 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007114 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007115
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007116 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7117 hdev);
7118
Johan Hedberg333ae952015-03-17 13:48:47 +02007119 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007120 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007121 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007122
Andre Guedes3655bba2013-10-30 19:01:40 -03007123 cp = cmd->param;
7124
7125 if (bacmp(bdaddr, &cp->addr.bdaddr))
7126 return;
7127
7128 if (cp->addr.type != bdaddr_type)
7129 return;
7130
Johan Hedbergf5818c22014-12-05 13:36:02 +02007131 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007132 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007133}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007134
Marcel Holtmann445608d2013-10-06 23:55:48 -07007135void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7136 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007137{
7138 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007139
Johan Hedberg84c61d92014-08-01 11:13:30 +03007140 /* The connection is still in hci_conn_hash so test for 1
7141 * instead of 0 to know if this is the last one.
7142 */
7143 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7144 cancel_delayed_work(&hdev->power_off);
7145 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007146 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007147
Johan Hedberg4c659c32011-11-07 23:13:39 +02007148 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007149 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007150 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007151
Marcel Holtmann445608d2013-10-06 23:55:48 -07007152 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007153}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007154
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007155void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007156{
7157 struct mgmt_ev_pin_code_request ev;
7158
Johan Hedbergd8457692012-02-17 14:24:57 +02007159 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007160 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007161 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007162
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007163 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007164}
7165
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007166void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7167 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007168{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007169 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007170
Johan Hedberg333ae952015-03-17 13:48:47 +02007171 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007172 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007173 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007174
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007175 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007176 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007177}
7178
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007179void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7180 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007181{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007182 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007183
Johan Hedberg333ae952015-03-17 13:48:47 +02007184 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007185 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007186 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007187
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007188 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007189 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007190}
Johan Hedberga5c29682011-02-19 12:05:57 -03007191
Johan Hedberg744cf192011-11-08 20:40:14 +02007192int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007193 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007194 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007195{
7196 struct mgmt_ev_user_confirm_request ev;
7197
Johan Hedberg744cf192011-11-08 20:40:14 +02007198 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007199
Johan Hedberg272d90d2012-02-09 15:26:12 +02007200 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007201 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007202 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007203 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007204
Johan Hedberg744cf192011-11-08 20:40:14 +02007205 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007206 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007207}
7208
Johan Hedberg272d90d2012-02-09 15:26:12 +02007209int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007210 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007211{
7212 struct mgmt_ev_user_passkey_request ev;
7213
7214 BT_DBG("%s", hdev->name);
7215
Johan Hedberg272d90d2012-02-09 15:26:12 +02007216 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007217 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007218
7219 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007220 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007221}
7222
Brian Gix0df4c182011-11-16 13:53:13 -08007223static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007224 u8 link_type, u8 addr_type, u8 status,
7225 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007226{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007227 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007228
Johan Hedberg333ae952015-03-17 13:48:47 +02007229 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007230 if (!cmd)
7231 return -ENOENT;
7232
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007233 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007234 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007235
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007236 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007237}
7238
Johan Hedberg744cf192011-11-08 20:40:14 +02007239int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007240 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007241{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007242 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007243 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007244}
7245
Johan Hedberg272d90d2012-02-09 15:26:12 +02007246int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007247 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007248{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007249 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007250 status,
7251 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007252}
Johan Hedberg2a611692011-02-19 12:06:00 -03007253
Brian Gix604086b2011-11-23 08:28:33 -08007254int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007255 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007256{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007257 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007258 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007259}
7260
Johan Hedberg272d90d2012-02-09 15:26:12 +02007261int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007262 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007263{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007264 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007265 status,
7266 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007267}
7268
Johan Hedberg92a25252012-09-06 18:39:26 +03007269int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7270 u8 link_type, u8 addr_type, u32 passkey,
7271 u8 entered)
7272{
7273 struct mgmt_ev_passkey_notify ev;
7274
7275 BT_DBG("%s", hdev->name);
7276
7277 bacpy(&ev.addr.bdaddr, bdaddr);
7278 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7279 ev.passkey = __cpu_to_le32(passkey);
7280 ev.entered = entered;
7281
7282 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7283}
7284
Johan Hedberge1e930f2014-09-08 17:09:49 -07007285void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007286{
7287 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007288 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007289 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007290
Johan Hedberge1e930f2014-09-08 17:09:49 -07007291 bacpy(&ev.addr.bdaddr, &conn->dst);
7292 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7293 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007294
Johan Hedberge1e930f2014-09-08 17:09:49 -07007295 cmd = find_pairing(conn);
7296
7297 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7298 cmd ? cmd->sk : NULL);
7299
Johan Hedberga511b352014-12-11 21:45:45 +02007300 if (cmd) {
7301 cmd->cmd_complete(cmd, status);
7302 mgmt_pending_remove(cmd);
7303 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007304}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007305
Marcel Holtmann464996a2013-10-15 14:26:24 -07007306void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007307{
7308 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007309 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007310
7311 if (status) {
7312 u8 mgmt_err = mgmt_status(status);
7313 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007314 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007315 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007316 }
7317
Marcel Holtmann464996a2013-10-15 14:26:24 -07007318 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007319 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007320 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007321 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007322
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007323 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007324 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007325
Johan Hedberg47990ea2012-02-22 11:58:37 +02007326 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007327 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007328
7329 if (match.sk)
7330 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007331}
7332
Johan Hedberg890ea892013-03-15 17:06:52 -05007333static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007334{
Johan Hedberg890ea892013-03-15 17:06:52 -05007335 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007336 struct hci_cp_write_eir cp;
7337
Johan Hedberg976eb202012-10-24 21:12:01 +03007338 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007339 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007340
Johan Hedbergc80da272012-02-22 15:38:48 +02007341 memset(hdev->eir, 0, sizeof(hdev->eir));
7342
Johan Hedbergcacaf522012-02-21 00:52:42 +02007343 memset(&cp, 0, sizeof(cp));
7344
Johan Hedberg890ea892013-03-15 17:06:52 -05007345 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007346}
7347
Marcel Holtmann3e248562013-10-15 14:26:25 -07007348void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007349{
7350 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007351 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007352 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007353
7354 if (status) {
7355 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007356
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007357 if (enable && hci_dev_test_and_clear_flag(hdev,
7358 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007359 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007360 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007361 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007362
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007363 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7364 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007365 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007366 }
7367
7368 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007369 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007370 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007371 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007372 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007373 changed = hci_dev_test_and_clear_flag(hdev,
7374 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007375 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007376 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007377 }
7378
7379 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7380
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007381 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007382 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007383
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007384 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007385 sock_put(match.sk);
7386
Johan Hedberg890ea892013-03-15 17:06:52 -05007387 hci_req_init(&req, hdev);
7388
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007389 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7390 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007391 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7392 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007393 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007394 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007395 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007396 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007397
7398 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007399}
7400
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007401static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007402{
7403 struct cmd_lookup *match = data;
7404
Johan Hedberg90e70452012-02-23 23:09:40 +02007405 if (match->sk == NULL) {
7406 match->sk = cmd->sk;
7407 sock_hold(match->sk);
7408 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007409}
7410
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007411void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7412 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007413{
Johan Hedberg90e70452012-02-23 23:09:40 +02007414 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007415
Johan Hedberg92da6092013-03-15 17:06:55 -05007416 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7417 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7418 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007419
7420 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007421 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7422 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007423
7424 if (match.sk)
7425 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007426}
7427
Marcel Holtmann7667da32013-10-15 14:26:27 -07007428void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007429{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007430 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007431 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007432
Johan Hedberg13928972013-03-15 17:07:00 -05007433 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007434 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007435
7436 memset(&ev, 0, sizeof(ev));
7437 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007438 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007439
Johan Hedberg333ae952015-03-17 13:48:47 +02007440 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007441 if (!cmd) {
7442 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007443
Johan Hedberg13928972013-03-15 17:07:00 -05007444 /* If this is a HCI command related to powering on the
7445 * HCI dev don't send any mgmt signals.
7446 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007447 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007448 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007449 }
7450
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007451 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7452 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007453}
Szymon Jancc35938b2011-03-22 13:12:21 +01007454
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007455static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7456{
7457 int i;
7458
7459 for (i = 0; i < uuid_count; i++) {
7460 if (!memcmp(uuid, uuids[i], 16))
7461 return true;
7462 }
7463
7464 return false;
7465}
7466
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007467static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7468{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007469 u16 parsed = 0;
7470
7471 while (parsed < eir_len) {
7472 u8 field_len = eir[0];
7473 u8 uuid[16];
7474 int i;
7475
7476 if (field_len == 0)
7477 break;
7478
7479 if (eir_len - parsed < field_len + 1)
7480 break;
7481
7482 switch (eir[1]) {
7483 case EIR_UUID16_ALL:
7484 case EIR_UUID16_SOME:
7485 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007486 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007487 uuid[13] = eir[i + 3];
7488 uuid[12] = eir[i + 2];
7489 if (has_uuid(uuid, uuid_count, uuids))
7490 return true;
7491 }
7492 break;
7493 case EIR_UUID32_ALL:
7494 case EIR_UUID32_SOME:
7495 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007496 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007497 uuid[15] = eir[i + 5];
7498 uuid[14] = eir[i + 4];
7499 uuid[13] = eir[i + 3];
7500 uuid[12] = eir[i + 2];
7501 if (has_uuid(uuid, uuid_count, uuids))
7502 return true;
7503 }
7504 break;
7505 case EIR_UUID128_ALL:
7506 case EIR_UUID128_SOME:
7507 for (i = 0; i + 17 <= field_len; i += 16) {
7508 memcpy(uuid, eir + i + 2, 16);
7509 if (has_uuid(uuid, uuid_count, uuids))
7510 return true;
7511 }
7512 break;
7513 }
7514
7515 parsed += field_len + 1;
7516 eir += field_len + 1;
7517 }
7518
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007519 return false;
7520}
7521
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007522static void restart_le_scan(struct hci_dev *hdev)
7523{
7524 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007525 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007526 return;
7527
7528 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7529 hdev->discovery.scan_start +
7530 hdev->discovery.scan_duration))
7531 return;
7532
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007533 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007534 DISCOV_LE_RESTART_DELAY);
7535}
7536
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007537static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7538 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7539{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007540 /* If a RSSI threshold has been specified, and
7541 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7542 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7543 * is set, let it through for further processing, as we might need to
7544 * restart the scan.
7545 *
7546 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7547 * the results are also dropped.
7548 */
7549 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7550 (rssi == HCI_RSSI_INVALID ||
7551 (rssi < hdev->discovery.rssi &&
7552 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7553 return false;
7554
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007555 if (hdev->discovery.uuid_count != 0) {
7556 /* If a list of UUIDs is provided in filter, results with no
7557 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007558 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007559 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7560 hdev->discovery.uuids) &&
7561 !eir_has_uuids(scan_rsp, scan_rsp_len,
7562 hdev->discovery.uuid_count,
7563 hdev->discovery.uuids))
7564 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007565 }
7566
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007567 /* If duplicate filtering does not report RSSI changes, then restart
7568 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007569 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007570 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7571 restart_le_scan(hdev);
7572
7573 /* Validate RSSI value against the RSSI threshold once more. */
7574 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7575 rssi < hdev->discovery.rssi)
7576 return false;
7577 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007578
7579 return true;
7580}
7581
Marcel Holtmann901801b2013-10-06 23:55:51 -07007582void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007583 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7584 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007585{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007586 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007587 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007588 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007589
Johan Hedberg75ce2082014-07-02 22:42:01 +03007590 /* Don't send events for a non-kernel initiated discovery. With
7591 * LE one exception is if we have pend_le_reports > 0 in which
7592 * case we're doing passive scanning and want these events.
7593 */
7594 if (!hci_discovery_active(hdev)) {
7595 if (link_type == ACL_LINK)
7596 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007597 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007598 return;
7599 }
Andre Guedes12602d02013-04-30 15:29:40 -03007600
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007601 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007602 /* We are using service discovery */
7603 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7604 scan_rsp_len))
7605 return;
7606 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007607
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007608 /* Make sure that the buffer is big enough. The 5 extra bytes
7609 * are for the potential CoD field.
7610 */
7611 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007612 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007613
Johan Hedberg1dc06092012-01-15 21:01:23 +02007614 memset(buf, 0, sizeof(buf));
7615
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007616 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7617 * RSSI value was reported as 0 when not available. This behavior
7618 * is kept when using device discovery. This is required for full
7619 * backwards compatibility with the API.
7620 *
7621 * However when using service discovery, the value 127 will be
7622 * returned when the RSSI is not available.
7623 */
Szymon Janc91200e92015-01-22 16:57:05 +01007624 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7625 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007626 rssi = 0;
7627
Johan Hedberg841c5642014-07-07 12:45:54 +03007628 bacpy(&ev->addr.bdaddr, bdaddr);
7629 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007630 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007631 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007632
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007633 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007634 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007635 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007636
Johan Hedberg1dc06092012-01-15 21:01:23 +02007637 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7638 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007639 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007640
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007641 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007642 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007643 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007644
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007645 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7646 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007647
Marcel Holtmann901801b2013-10-06 23:55:51 -07007648 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007649}
Johan Hedberga88a9652011-03-30 13:18:12 +03007650
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007651void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7652 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007653{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007654 struct mgmt_ev_device_found *ev;
7655 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7656 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007657
Johan Hedbergb644ba32012-01-17 21:48:47 +02007658 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007659
Johan Hedbergb644ba32012-01-17 21:48:47 +02007660 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007661
Johan Hedbergb644ba32012-01-17 21:48:47 +02007662 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007663 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007664 ev->rssi = rssi;
7665
7666 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007667 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007668
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007669 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007670
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007671 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007672}
Johan Hedberg314b2382011-04-27 10:29:57 -04007673
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007674void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007675{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007676 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007677
Andre Guedes343fb142011-11-22 17:14:19 -03007678 BT_DBG("%s discovering %u", hdev->name, discovering);
7679
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007680 memset(&ev, 0, sizeof(ev));
7681 ev.type = hdev->discovery.type;
7682 ev.discovering = discovering;
7683
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007684 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007685}
Antti Julku5e762442011-08-25 16:48:02 +03007686
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007687static struct hci_mgmt_chan chan = {
7688 .channel = HCI_CHANNEL_CONTROL,
7689 .handler_count = ARRAY_SIZE(mgmt_handlers),
7690 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007691 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007692};
7693
7694int mgmt_init(void)
7695{
7696 return hci_mgmt_chan_register(&chan);
7697}
7698
7699void mgmt_exit(void)
7700{
7701 hci_mgmt_chan_unregister(&chan);
7702}