blob: f5a4ee92f2bf5ca7d5e245c002f34d2eae19e775 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Johan Hedbergdc4270c2015-11-23 15:07:51 +020041#define MGMT_REVISION 11
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
108static const u16 mgmt_events[] = {
109 MGMT_EV_CONTROLLER_ERROR,
110 MGMT_EV_INDEX_ADDED,
111 MGMT_EV_INDEX_REMOVED,
112 MGMT_EV_NEW_SETTINGS,
113 MGMT_EV_CLASS_OF_DEV_CHANGED,
114 MGMT_EV_LOCAL_NAME_CHANGED,
115 MGMT_EV_NEW_LINK_KEY,
116 MGMT_EV_NEW_LONG_TERM_KEY,
117 MGMT_EV_DEVICE_CONNECTED,
118 MGMT_EV_DEVICE_DISCONNECTED,
119 MGMT_EV_CONNECT_FAILED,
120 MGMT_EV_PIN_CODE_REQUEST,
121 MGMT_EV_USER_CONFIRM_REQUEST,
122 MGMT_EV_USER_PASSKEY_REQUEST,
123 MGMT_EV_AUTH_FAILED,
124 MGMT_EV_DEVICE_FOUND,
125 MGMT_EV_DISCOVERING,
126 MGMT_EV_DEVICE_BLOCKED,
127 MGMT_EV_DEVICE_UNBLOCKED,
128 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300129 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800130 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700131 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200132 MGMT_EV_DEVICE_ADDED,
133 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300134 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200135 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200136 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200137 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700138 MGMT_EV_EXT_INDEX_ADDED,
139 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700140 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700141 MGMT_EV_ADVERTISING_ADDED,
142 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200143};
144
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700145static const u16 mgmt_untrusted_commands[] = {
146 MGMT_OP_READ_INDEX_LIST,
147 MGMT_OP_READ_INFO,
148 MGMT_OP_READ_UNCONF_INDEX_LIST,
149 MGMT_OP_READ_CONFIG_INFO,
150 MGMT_OP_READ_EXT_INDEX_LIST,
151};
152
153static const u16 mgmt_untrusted_events[] = {
154 MGMT_EV_INDEX_ADDED,
155 MGMT_EV_INDEX_REMOVED,
156 MGMT_EV_NEW_SETTINGS,
157 MGMT_EV_CLASS_OF_DEV_CHANGED,
158 MGMT_EV_LOCAL_NAME_CHANGED,
159 MGMT_EV_UNCONF_INDEX_ADDED,
160 MGMT_EV_UNCONF_INDEX_REMOVED,
161 MGMT_EV_NEW_CONFIG_OPTIONS,
162 MGMT_EV_EXT_INDEX_ADDED,
163 MGMT_EV_EXT_INDEX_REMOVED,
164};
165
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800166#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200167
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200168#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
169 "\x00\x00\x00\x00\x00\x00\x00\x00"
170
Johan Hedbergca69b792011-11-11 18:10:00 +0200171/* HCI to MGMT error code conversion table */
172static u8 mgmt_status_table[] = {
173 MGMT_STATUS_SUCCESS,
174 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
175 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
176 MGMT_STATUS_FAILED, /* Hardware Failure */
177 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
178 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200179 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200180 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
181 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
182 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
184 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
185 MGMT_STATUS_BUSY, /* Command Disallowed */
186 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
187 MGMT_STATUS_REJECTED, /* Rejected Security */
188 MGMT_STATUS_REJECTED, /* Rejected Personal */
189 MGMT_STATUS_TIMEOUT, /* Host Timeout */
190 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
191 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
192 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
193 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
194 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
195 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
196 MGMT_STATUS_BUSY, /* Repeated Attempts */
197 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
198 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
199 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
200 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
201 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
202 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
203 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
204 MGMT_STATUS_FAILED, /* Unspecified Error */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
206 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
207 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
208 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
209 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
210 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
211 MGMT_STATUS_FAILED, /* Unit Link Key Used */
212 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
213 MGMT_STATUS_TIMEOUT, /* Instant Passed */
214 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
215 MGMT_STATUS_FAILED, /* Transaction Collision */
216 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
217 MGMT_STATUS_REJECTED, /* QoS Rejected */
218 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
219 MGMT_STATUS_REJECTED, /* Insufficient Security */
220 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
221 MGMT_STATUS_BUSY, /* Role Switch Pending */
222 MGMT_STATUS_FAILED, /* Slot Violation */
223 MGMT_STATUS_FAILED, /* Role Switch Failed */
224 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
225 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
226 MGMT_STATUS_BUSY, /* Host Busy Pairing */
227 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
228 MGMT_STATUS_BUSY, /* Controller Busy */
229 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
230 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
231 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
232 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
233 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
234};
235
236static u8 mgmt_status(u8 hci_status)
237{
238 if (hci_status < ARRAY_SIZE(mgmt_status_table))
239 return mgmt_status_table[hci_status];
240
241 return MGMT_STATUS_FAILED;
242}
243
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700244static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
245 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700246{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700247 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
248 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700249}
250
Marcel Holtmann72000df2015-03-16 16:11:21 -0700251static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
252 u16 len, int flag, struct sock *skip_sk)
253{
254 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
255 flag, skip_sk);
256}
257
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700258static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
259 u16 len, struct sock *skip_sk)
260{
261 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
262 HCI_MGMT_GENERIC_EVENTS, skip_sk);
263}
264
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200265static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
266 struct sock *skip_sk)
267{
268 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700269 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200270}
271
Johan Hedberg85813a72015-10-21 18:02:59 +0300272static u8 le_addr_type(u8 mgmt_addr_type)
273{
274 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
275 return ADDR_LE_DEV_PUBLIC;
276 else
277 return ADDR_LE_DEV_RANDOM;
278}
279
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300280static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
281 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200282{
283 struct mgmt_rp_read_version rp;
284
285 BT_DBG("sock %p", sk);
286
287 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700288 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200289
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200290 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
291 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200292}
293
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300294static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
295 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296{
297 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700298 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200299 size_t rp_size;
300 int i, err;
301
302 BT_DBG("sock %p", sk);
303
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
305 num_commands = ARRAY_SIZE(mgmt_commands);
306 num_events = ARRAY_SIZE(mgmt_events);
307 } else {
308 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
309 num_events = ARRAY_SIZE(mgmt_untrusted_events);
310 }
311
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
313
314 rp = kmalloc(rp_size, GFP_KERNEL);
315 if (!rp)
316 return -ENOMEM;
317
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700318 rp->num_commands = cpu_to_le16(num_commands);
319 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700321 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
322 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200323
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700324 for (i = 0; i < num_commands; i++, opcode++)
325 put_unaligned_le16(mgmt_commands[i], opcode);
326
327 for (i = 0; i < num_events; i++, opcode++)
328 put_unaligned_le16(mgmt_events[i], opcode);
329 } else {
330 __le16 *opcode = rp->opcodes;
331
332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
337 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200338
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200339 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
340 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200341 kfree(rp);
342
343 return err;
344}
345
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300346static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
347 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200351 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
355 BT_DBG("sock %p", sk);
356
357 read_lock(&hci_dev_list_lock);
358
359 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300360 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200361 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700362 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700363 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364 }
365
Johan Hedberga38528f2011-01-22 06:46:43 +0200366 rp_len = sizeof(*rp) + (2 * count);
367 rp = kmalloc(rp_len, GFP_ATOMIC);
368 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100369 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100371 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372
Johan Hedberg476e44c2012-10-19 20:10:46 +0300373 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200374 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700375 if (hci_dev_test_flag(d, HCI_SETUP) ||
376 hci_dev_test_flag(d, HCI_CONFIG) ||
377 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200378 continue;
379
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200380 /* Devices marked as raw-only are neither configured
381 * nor unconfigured controllers.
382 */
383 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700387 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700388 rp->index[count++] = cpu_to_le16(d->id);
389 BT_DBG("Added hci%u", d->id);
390 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391 }
392
Johan Hedberg476e44c2012-10-19 20:10:46 +0300393 rp->num_controllers = cpu_to_le16(count);
394 rp_len = sizeof(*rp) + (2 * count);
395
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 read_unlock(&hci_dev_list_lock);
397
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200398 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
399 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400
Johan Hedberga38528f2011-01-22 06:46:43 +0200401 kfree(rp);
402
403 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404}
405
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200406static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
407 void *data, u16 data_len)
408{
409 struct mgmt_rp_read_unconf_index_list *rp;
410 struct hci_dev *d;
411 size_t rp_len;
412 u16 count;
413 int err;
414
415 BT_DBG("sock %p", sk);
416
417 read_lock(&hci_dev_list_lock);
418
419 count = 0;
420 list_for_each_entry(d, &hci_dev_list, list) {
421 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700422 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200423 count++;
424 }
425
426 rp_len = sizeof(*rp) + (2 * count);
427 rp = kmalloc(rp_len, GFP_ATOMIC);
428 if (!rp) {
429 read_unlock(&hci_dev_list_lock);
430 return -ENOMEM;
431 }
432
433 count = 0;
434 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700435 if (hci_dev_test_flag(d, HCI_SETUP) ||
436 hci_dev_test_flag(d, HCI_CONFIG) ||
437 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438 continue;
439
440 /* Devices marked as raw-only are neither configured
441 * nor unconfigured controllers.
442 */
443 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
444 continue;
445
446 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700447 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448 rp->index[count++] = cpu_to_le16(d->id);
449 BT_DBG("Added hci%u", d->id);
450 }
451 }
452
453 rp->num_controllers = cpu_to_le16(count);
454 rp_len = sizeof(*rp) + (2 * count);
455
456 read_unlock(&hci_dev_list_lock);
457
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200458 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
459 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200460
461 kfree(rp);
462
463 return err;
464}
465
Marcel Holtmann96f14742015-03-14 19:27:57 -0700466static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
467 void *data, u16 data_len)
468{
469 struct mgmt_rp_read_ext_index_list *rp;
470 struct hci_dev *d;
471 size_t rp_len;
472 u16 count;
473 int err;
474
475 BT_DBG("sock %p", sk);
476
477 read_lock(&hci_dev_list_lock);
478
479 count = 0;
480 list_for_each_entry(d, &hci_dev_list, list) {
481 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
482 count++;
483 }
484
485 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
486 rp = kmalloc(rp_len, GFP_ATOMIC);
487 if (!rp) {
488 read_unlock(&hci_dev_list_lock);
489 return -ENOMEM;
490 }
491
492 count = 0;
493 list_for_each_entry(d, &hci_dev_list, list) {
494 if (hci_dev_test_flag(d, HCI_SETUP) ||
495 hci_dev_test_flag(d, HCI_CONFIG) ||
496 hci_dev_test_flag(d, HCI_USER_CHANNEL))
497 continue;
498
499 /* Devices marked as raw-only are neither configured
500 * nor unconfigured controllers.
501 */
502 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
503 continue;
504
505 if (d->dev_type == HCI_BREDR) {
506 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
507 rp->entry[count].type = 0x01;
508 else
509 rp->entry[count].type = 0x00;
510 } else if (d->dev_type == HCI_AMP) {
511 rp->entry[count].type = 0x02;
512 } else {
513 continue;
514 }
515
516 rp->entry[count].bus = d->bus;
517 rp->entry[count++].index = cpu_to_le16(d->id);
518 BT_DBG("Added hci%u", d->id);
519 }
520
521 rp->num_controllers = cpu_to_le16(count);
522 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
523
524 read_unlock(&hci_dev_list_lock);
525
526 /* If this command is called at least once, then all the
527 * default index and unconfigured index events are disabled
528 * and from now on only extended index events are used.
529 */
530 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
531 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
532 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
533
534 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
535 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
536
537 kfree(rp);
538
539 return err;
540}
541
Marcel Holtmanndbece372014-07-04 18:11:55 +0200542static bool is_configured(struct hci_dev *hdev)
543{
544 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700545 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200546 return false;
547
548 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
549 !bacmp(&hdev->public_addr, BDADDR_ANY))
550 return false;
551
552 return true;
553}
554
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200555static __le32 get_missing_options(struct hci_dev *hdev)
556{
557 u32 options = 0;
558
Marcel Holtmanndbece372014-07-04 18:11:55 +0200559 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700560 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200561 options |= MGMT_OPTION_EXTERNAL_CONFIG;
562
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200563 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
564 !bacmp(&hdev->public_addr, BDADDR_ANY))
565 options |= MGMT_OPTION_PUBLIC_ADDRESS;
566
567 return cpu_to_le32(options);
568}
569
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200570static int new_options(struct hci_dev *hdev, struct sock *skip)
571{
572 __le32 options = get_missing_options(hdev);
573
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700574 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
575 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576}
577
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
579{
580 __le32 options = get_missing_options(hdev);
581
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200582 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
583 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584}
585
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200586static int read_config_info(struct sock *sk, struct hci_dev *hdev,
587 void *data, u16 data_len)
588{
589 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200590 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591
592 BT_DBG("sock %p %s", sk, hdev->name);
593
594 hci_dev_lock(hdev);
595
596 memset(&rp, 0, sizeof(rp));
597 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
600 options |= MGMT_OPTION_EXTERNAL_CONFIG;
601
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200602 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603 options |= MGMT_OPTION_PUBLIC_ADDRESS;
604
605 rp.supported_options = cpu_to_le32(options);
606 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607
608 hci_dev_unlock(hdev);
609
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
611 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612}
613
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200614static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200615{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200617
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300619 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800620 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300621 settings |= MGMT_SETTING_CONNECTABLE;
622 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Andre Guedesed3fa312012-07-24 15:03:46 -0300624 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500625 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
626 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627 settings |= MGMT_SETTING_BREDR;
628 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700629
630 if (lmp_ssp_capable(hdev)) {
631 settings |= MGMT_SETTING_SSP;
632 settings |= MGMT_SETTING_HS;
633 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800634
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800635 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800636 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700637 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100638
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300639 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200640 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300641 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300642 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200643 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800644 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300645 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200646
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200647 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
648 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200649 settings |= MGMT_SETTING_CONFIGURATION;
650
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651 return settings;
652}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200653
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200654static u32 get_current_settings(struct hci_dev *hdev)
655{
656 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200657
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200658 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100659 settings |= MGMT_SETTING_POWERED;
660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662 settings |= MGMT_SETTING_CONNECTABLE;
663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700664 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500665 settings |= MGMT_SETTING_FAST_CONNECTABLE;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_DISCOVERABLE;
669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300671 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_BREDR;
675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200683 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200686 settings |= MGMT_SETTING_HS;
687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300689 settings |= MGMT_SETTING_ADVERTISING;
690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700691 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800692 settings |= MGMT_SETTING_SECURE_CONN;
693
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700694 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800695 settings |= MGMT_SETTING_DEBUG_KEYS;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200698 settings |= MGMT_SETTING_PRIVACY;
699
Marcel Holtmann93690c22015-03-06 10:11:21 -0800700 /* The current setting for static address has two purposes. The
701 * first is to indicate if the static address will be used and
702 * the second is to indicate if it is actually set.
703 *
704 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700705 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800706 * address is actually used decides if the flag is set or not.
707 *
708 * For single mode LE only controllers and dual-mode controllers
709 * with BR/EDR disabled, the existence of the static address will
710 * be evaluated.
711 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700712 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700713 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800714 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
715 if (bacmp(&hdev->static_addr, BDADDR_ANY))
716 settings |= MGMT_SETTING_STATIC_ADDRESS;
717 }
718
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200720}
721
Johan 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
Marcel Holtmann1904a852015-01-11 13:50:44 -08001285static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1286 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001287{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001288 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001289 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001290 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001291 bool changed;
1292
1293 BT_DBG("status 0x%02x", status);
1294
1295 hci_dev_lock(hdev);
1296
Johan Hedberg333ae952015-03-17 13:48:47 +02001297 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001298 if (!cmd)
1299 goto unlock;
1300
1301 if (status) {
1302 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001303 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001304 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001305 goto remove_cmd;
1306 }
1307
1308 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001309 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001310 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001311
1312 if (hdev->discov_timeout > 0) {
1313 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1314 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1315 to);
1316 }
1317 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001318 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001319 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001320
1321 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1322
1323 if (changed)
1324 new_settings(hdev, cmd->sk);
1325
Marcel Holtmann970ba522013-10-15 06:33:57 -07001326 /* When the discoverable mode gets changed, make sure
1327 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001328 * bit correctly set. Also update page scan based on whitelist
1329 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001330 */
1331 hci_req_init(&req, hdev);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001332 __hci_req_update_scan(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001333 __hci_req_update_class(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001334 hci_req_run(&req, NULL);
1335
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001336remove_cmd:
1337 mgmt_pending_remove(cmd);
1338
1339unlock:
1340 hci_dev_unlock(hdev);
1341}
1342
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001343static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001344 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001345{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001346 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001347 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001348 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001349 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001350 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001351 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001353 BT_DBG("request for %s", hdev->name);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001354
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001355 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1356 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001357 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1358 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001359
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001360 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001361 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1362 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001363
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001364 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001365
1366 /* Disabling discoverable requires that no timeout is set,
1367 * and enabling limited discoverable requires a timeout.
1368 */
1369 if ((cp->val == 0x00 && timeout > 0) ||
1370 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001371 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1372 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001373
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001374 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001375
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001376 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001377 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1378 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001379 goto failed;
1380 }
1381
Johan Hedberg333ae952015-03-17 13:48:47 +02001382 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1383 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001384 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1385 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001386 goto failed;
1387 }
1388
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001389 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001390 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1391 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001392 goto failed;
1393 }
1394
1395 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001396 bool changed = false;
1397
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001398 /* Setting limited discoverable when powered off is
1399 * not a valid operation since it requires a timeout
1400 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1401 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001402 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001403 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001404 changed = true;
1405 }
1406
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001407 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001408 if (err < 0)
1409 goto failed;
1410
1411 if (changed)
1412 err = new_settings(hdev, sk);
1413
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001414 goto failed;
1415 }
1416
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001417 /* If the current mode is the same, then just update the timeout
1418 * value with the new value. And if only the timeout gets updated,
1419 * then no need for any HCI transactions.
1420 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001421 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1422 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1423 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001424 cancel_delayed_work(&hdev->discov_off);
1425 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001426
Marcel Holtmann36261542013-10-15 08:28:51 -07001427 if (cp->val && hdev->discov_timeout > 0) {
1428 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001429 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001430 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001431 }
1432
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001433 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001434 goto failed;
1435 }
1436
1437 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1438 if (!cmd) {
1439 err = -ENOMEM;
1440 goto failed;
1441 }
1442
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001443 /* Cancel any potential discoverable timeout that might be
1444 * still active and store new timeout value. The arming of
1445 * the timeout happens in the complete handler.
1446 */
1447 cancel_delayed_work(&hdev->discov_off);
1448 hdev->discov_timeout = timeout;
1449
Johan Hedbergb456f872013-10-19 23:38:22 +03001450 /* Limited discoverable mode */
1451 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001452 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001453 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001454 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001455
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001456 hci_req_init(&req, hdev);
1457
Johan Hedberg9a43e252013-10-20 19:00:07 +03001458 /* The procedure for LE-only controllers is much simpler - just
1459 * update the advertising data.
1460 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001461 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001462 goto update_ad;
1463
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001464 scan = SCAN_PAGE;
1465
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001466 if (cp->val) {
1467 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001468
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001469 if (cp->val == 0x02) {
1470 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001471 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001472 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1473 hci_cp.iac_lap[1] = 0x8b;
1474 hci_cp.iac_lap[2] = 0x9e;
1475 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1476 hci_cp.iac_lap[4] = 0x8b;
1477 hci_cp.iac_lap[5] = 0x9e;
1478 } else {
1479 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001480 hci_cp.num_iac = 1;
1481 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1482 hci_cp.iac_lap[1] = 0x8b;
1483 hci_cp.iac_lap[2] = 0x9e;
1484 }
1485
1486 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1487 (hci_cp.num_iac * 3) + 1, &hci_cp);
1488
1489 scan |= SCAN_INQUIRY;
1490 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001491 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001492 }
1493
1494 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001495
Johan Hedberg9a43e252013-10-20 19:00:07 +03001496update_ad:
Johan Hedbergf2252572015-11-18 12:49:20 +02001497 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedberg9a43e252013-10-20 19:00:07 +03001498
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001499 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001500 if (err < 0)
1501 mgmt_pending_remove(cmd);
1502
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001503failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001504 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001505 return err;
1506}
1507
Johan Hedberg406d7802013-03-15 17:07:09 -05001508static void write_fast_connectable(struct hci_request *req, bool enable)
1509{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001510 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001511 struct hci_cp_write_page_scan_activity acp;
1512 u8 type;
1513
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001514 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001515 return;
1516
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001517 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1518 return;
1519
Johan Hedberg406d7802013-03-15 17:07:09 -05001520 if (enable) {
1521 type = PAGE_SCAN_TYPE_INTERLACED;
1522
1523 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001524 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001525 } else {
1526 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1527
1528 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001529 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001530 }
1531
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001532 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001533
Johan Hedbergbd98b992013-03-15 17:07:13 -05001534 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1535 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1536 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1537 sizeof(acp), &acp);
1538
1539 if (hdev->page_scan_type != type)
1540 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001541}
1542
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001543void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001544{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001545 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001546
1547 BT_DBG("status 0x%02x", status);
1548
1549 hci_dev_lock(hdev);
1550
Johan Hedberg333ae952015-03-17 13:48:47 +02001551 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001552 if (!cmd)
1553 goto unlock;
1554
Johan Hedberg37438c12013-10-14 16:20:05 +03001555 if (status) {
1556 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001557 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001558 goto remove_cmd;
1559 }
1560
Johan Hedberg2b76f452013-03-15 17:07:04 -05001561 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001562 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001563
Johan Hedberg37438c12013-10-14 16:20:05 +03001564remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001565 mgmt_pending_remove(cmd);
1566
1567unlock:
1568 hci_dev_unlock(hdev);
1569}
1570
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001571static int set_connectable_update_settings(struct hci_dev *hdev,
1572 struct sock *sk, u8 val)
1573{
1574 bool changed = false;
1575 int err;
1576
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001577 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001578 changed = true;
1579
1580 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001581 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001582 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001583 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1584 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001585 }
1586
1587 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1588 if (err < 0)
1589 return err;
1590
Johan Hedberg562064e2014-07-08 16:35:34 +03001591 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001592 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001593 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001594 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001595 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001596
1597 return 0;
1598}
1599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001600static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001601 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001602{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001603 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001604 struct mgmt_pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001605 int err;
1606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001607 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001608
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001609 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1610 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001611 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1612 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001613
Johan Hedberga7e80f22013-01-09 16:05:19 +02001614 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001615 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1616 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001617
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001618 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001619
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001620 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001621 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001622 goto failed;
1623 }
1624
Johan Hedberg333ae952015-03-17 13:48:47 +02001625 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1626 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001627 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1628 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001629 goto failed;
1630 }
1631
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001632 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1633 if (!cmd) {
1634 err = -ENOMEM;
1635 goto failed;
1636 }
1637
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001638 if (cp->val) {
1639 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1640 } else {
1641 if (hdev->discov_timeout > 0)
1642 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001643
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001644 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1645 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1646 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001647 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001648
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001649 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1650 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001651
1652failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001653 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001654 return err;
1655}
1656
Johan Hedbergb2939472014-07-30 09:22:23 +03001657static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001658 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001659{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001660 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001661 bool changed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001662 int err;
1663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001664 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001665
Johan Hedberga7e80f22013-01-09 16:05:19 +02001666 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001667 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1668 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001669
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001670 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001671
1672 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001673 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001674 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001675 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001676
Johan Hedbergb2939472014-07-30 09:22:23 +03001677 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001678 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001679 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001680
Marcel Holtmann55594352013-10-06 16:11:57 -07001681 if (changed)
1682 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001683
Marcel Holtmann55594352013-10-06 16:11:57 -07001684unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001685 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001686 return err;
1687}
1688
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001689static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1690 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001691{
1692 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001693 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001694 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001695 int err;
1696
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001697 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001698
Johan Hedberge6fe7982013-10-02 15:45:22 +03001699 status = mgmt_bredr_support(hdev);
1700 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001701 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1702 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001703
Johan Hedberga7e80f22013-01-09 16:05:19 +02001704 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001705 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1706 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001707
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001708 hci_dev_lock(hdev);
1709
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001710 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001711 bool changed = false;
1712
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001713 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001714 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001715 changed = true;
1716 }
1717
1718 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1719 if (err < 0)
1720 goto failed;
1721
1722 if (changed)
1723 err = new_settings(hdev, sk);
1724
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001725 goto failed;
1726 }
1727
Johan Hedberg333ae952015-03-17 13:48:47 +02001728 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001729 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1730 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001731 goto failed;
1732 }
1733
1734 val = !!cp->val;
1735
1736 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1737 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1738 goto failed;
1739 }
1740
1741 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1742 if (!cmd) {
1743 err = -ENOMEM;
1744 goto failed;
1745 }
1746
1747 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1748 if (err < 0) {
1749 mgmt_pending_remove(cmd);
1750 goto failed;
1751 }
1752
1753failed:
1754 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001755 return err;
1756}
1757
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001758static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001759{
1760 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001761 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001762 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001763 int err;
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001766
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001767 status = mgmt_bredr_support(hdev);
1768 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001769 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001770
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001771 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001772 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1773 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001774
Johan Hedberga7e80f22013-01-09 16:05:19 +02001775 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001776 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1777 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001778
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001779 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001780
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001781 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001782 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001783
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001784 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001785 changed = !hci_dev_test_and_set_flag(hdev,
1786 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001787 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001788 changed = hci_dev_test_and_clear_flag(hdev,
1789 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001790 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001791 changed = hci_dev_test_and_clear_flag(hdev,
1792 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001793 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001794 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001795 }
1796
1797 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1798 if (err < 0)
1799 goto failed;
1800
1801 if (changed)
1802 err = new_settings(hdev, sk);
1803
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001804 goto failed;
1805 }
1806
Johan Hedberg333ae952015-03-17 13:48:47 +02001807 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001808 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1809 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001810 goto failed;
1811 }
1812
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001813 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001814 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1815 goto failed;
1816 }
1817
1818 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1819 if (!cmd) {
1820 err = -ENOMEM;
1821 goto failed;
1822 }
1823
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001824 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001825 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1826 sizeof(cp->val), &cp->val);
1827
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001828 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001829 if (err < 0) {
1830 mgmt_pending_remove(cmd);
1831 goto failed;
1832 }
1833
1834failed:
1835 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001836 return err;
1837}
1838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001839static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001840{
1841 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001842 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001843 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001844 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001845
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001846 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001847
Johan Hedberge6fe7982013-10-02 15:45:22 +03001848 status = mgmt_bredr_support(hdev);
1849 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001850 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001851
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001852 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001853 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1854 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001855
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001856 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001857 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1858 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001859
Johan Hedberga7e80f22013-01-09 16:05:19 +02001860 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001861 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1862 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001863
Marcel Holtmannee392692013-10-01 22:59:23 -07001864 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001865
Johan Hedberg333ae952015-03-17 13:48:47 +02001866 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001867 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1868 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001869 goto unlock;
1870 }
1871
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001872 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001873 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001874 } else {
1875 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001876 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1877 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001878 goto unlock;
1879 }
1880
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001881 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001882 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001883
1884 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1885 if (err < 0)
1886 goto unlock;
1887
1888 if (changed)
1889 err = new_settings(hdev, sk);
1890
1891unlock:
1892 hci_dev_unlock(hdev);
1893 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001894}
1895
Marcel Holtmann1904a852015-01-11 13:50:44 -08001896static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001897{
1898 struct cmd_lookup match = { NULL, hdev };
1899
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301900 hci_dev_lock(hdev);
1901
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001902 if (status) {
1903 u8 mgmt_err = mgmt_status(status);
1904
1905 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1906 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301907 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001908 }
1909
1910 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1911
1912 new_settings(hdev, match.sk);
1913
1914 if (match.sk)
1915 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001916
1917 /* Make sure the controller has a good default for
1918 * advertising data. Restrict the update to when LE
1919 * has actually been enabled. During power on, the
1920 * update in powered_update_hci will take care of it.
1921 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001922 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001923 struct hci_request req;
1924
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001925 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001926 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
1927 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001928 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001929 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001930 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301931
1932unlock:
1933 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001934}
1935
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001936static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001937{
1938 struct mgmt_mode *cp = data;
1939 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001940 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001941 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001942 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001943 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001944
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001945 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001946
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001947 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001948 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1949 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001950
Johan Hedberga7e80f22013-01-09 16:05:19 +02001951 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001952 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1953 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001954
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001955 /* Bluetooth single mode LE only controllers or dual-mode
1956 * controllers configured as LE only devices, do not allow
1957 * switching LE off. These have either LE enabled explicitly
1958 * or BR/EDR has been previously switched off.
1959 *
1960 * When trying to enable an already enabled LE, then gracefully
1961 * send a positive response. Trying to disable it however will
1962 * result into rejection.
1963 */
1964 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1965 if (cp->val == 0x01)
1966 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1967
Johan Hedberga69e8372015-03-06 21:08:53 +02001968 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1969 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001970 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001971
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001972 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001973
1974 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001975 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001976
Florian Grandel847818d2015-06-18 03:16:46 +02001977 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02001978 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001979
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001980 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001981 bool changed = false;
1982
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001983 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001984 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001985 changed = true;
1986 }
1987
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001988 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001989 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001990 changed = true;
1991 }
1992
Johan Hedberg06199cf2012-02-22 16:37:11 +02001993 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1994 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001995 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001996
1997 if (changed)
1998 err = new_settings(hdev, sk);
1999
Johan Hedberg1de028c2012-02-29 19:55:35 -08002000 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002001 }
2002
Johan Hedberg333ae952015-03-17 13:48:47 +02002003 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2004 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002005 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2006 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002007 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002008 }
2009
2010 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2011 if (!cmd) {
2012 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002013 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002014 }
2015
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002016 hci_req_init(&req, hdev);
2017
Johan Hedberg06199cf2012-02-22 16:37:11 +02002018 memset(&hci_cp, 0, sizeof(hci_cp));
2019
2020 if (val) {
2021 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002022 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002023 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002024 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02002025 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002026 }
2027
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002028 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2029 &hci_cp);
2030
2031 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302032 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002033 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002034
Johan Hedberg1de028c2012-02-29 19:55:35 -08002035unlock:
2036 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002037 return err;
2038}
2039
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002040/* This is a helper function to test for pending mgmt commands that can
2041 * cause CoD or EIR HCI commands. We can only allow one such pending
2042 * mgmt command at a time since otherwise we cannot easily track what
2043 * the current values are, will be, and based on that calculate if a new
2044 * HCI command needs to be sent and if yes with what value.
2045 */
2046static bool pending_eir_or_class(struct hci_dev *hdev)
2047{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002048 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002049
2050 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2051 switch (cmd->opcode) {
2052 case MGMT_OP_ADD_UUID:
2053 case MGMT_OP_REMOVE_UUID:
2054 case MGMT_OP_SET_DEV_CLASS:
2055 case MGMT_OP_SET_POWERED:
2056 return true;
2057 }
2058 }
2059
2060 return false;
2061}
2062
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002063static const u8 bluetooth_base_uuid[] = {
2064 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2065 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2066};
2067
2068static u8 get_uuid_size(const u8 *uuid)
2069{
2070 u32 val;
2071
2072 if (memcmp(uuid, bluetooth_base_uuid, 12))
2073 return 128;
2074
2075 val = get_unaligned_le32(&uuid[12]);
2076 if (val > 0xffff)
2077 return 32;
2078
2079 return 16;
2080}
2081
Johan Hedberg92da6092013-03-15 17:06:55 -05002082static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2083{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002084 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002085
2086 hci_dev_lock(hdev);
2087
Johan Hedberg333ae952015-03-17 13:48:47 +02002088 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002089 if (!cmd)
2090 goto unlock;
2091
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002092 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2093 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002094
2095 mgmt_pending_remove(cmd);
2096
2097unlock:
2098 hci_dev_unlock(hdev);
2099}
2100
Marcel Holtmann1904a852015-01-11 13:50:44 -08002101static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002102{
2103 BT_DBG("status 0x%02x", status);
2104
2105 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2106}
2107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002108static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002109{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002110 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002111 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002112 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002113 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002114 int err;
2115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002117
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002118 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002120 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002121 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2122 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002123 goto failed;
2124 }
2125
Andre Guedes92c4c202012-06-07 19:05:44 -03002126 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002127 if (!uuid) {
2128 err = -ENOMEM;
2129 goto failed;
2130 }
2131
2132 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002133 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002134 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002135
Johan Hedbergde66aa62013-01-27 00:31:27 +02002136 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002137
Johan Hedberg890ea892013-03-15 17:06:52 -05002138 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002139
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002140 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002141 update_eir(&req);
2142
Johan Hedberg92da6092013-03-15 17:06:55 -05002143 err = hci_req_run(&req, add_uuid_complete);
2144 if (err < 0) {
2145 if (err != -ENODATA)
2146 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002147
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002148 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2149 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002150 goto failed;
2151 }
2152
2153 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002154 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002155 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002156 goto failed;
2157 }
2158
2159 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002160
2161failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002162 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002163 return err;
2164}
2165
Johan Hedberg24b78d02012-02-23 23:24:30 +02002166static bool enable_service_cache(struct hci_dev *hdev)
2167{
2168 if (!hdev_is_powered(hdev))
2169 return false;
2170
Marcel Holtmann238be782015-03-13 02:11:06 -07002171 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002172 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2173 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002174 return true;
2175 }
2176
2177 return false;
2178}
2179
Marcel Holtmann1904a852015-01-11 13:50:44 -08002180static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002181{
2182 BT_DBG("status 0x%02x", status);
2183
2184 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2185}
2186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002188 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002189{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002190 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002191 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002192 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002193 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 -05002194 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002195 int err, found;
2196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002197 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002198
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002199 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002200
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002201 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002202 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2203 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002204 goto unlock;
2205 }
2206
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002207 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002208 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002209
Johan Hedberg24b78d02012-02-23 23:24:30 +02002210 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002211 err = mgmt_cmd_complete(sk, hdev->id,
2212 MGMT_OP_REMOVE_UUID,
2213 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002214 goto unlock;
2215 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002216
Johan Hedberg9246a862012-02-23 21:33:16 +02002217 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002218 }
2219
2220 found = 0;
2221
Johan Hedberg056341c2013-01-27 00:31:30 +02002222 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002223 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2224 continue;
2225
2226 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002227 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002228 found++;
2229 }
2230
2231 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002234 goto unlock;
2235 }
2236
Johan Hedberg9246a862012-02-23 21:33:16 +02002237update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002238 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002239
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002240 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002241 update_eir(&req);
2242
Johan Hedberg92da6092013-03-15 17:06:55 -05002243 err = hci_req_run(&req, remove_uuid_complete);
2244 if (err < 0) {
2245 if (err != -ENODATA)
2246 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002247
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002248 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2249 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002250 goto unlock;
2251 }
2252
2253 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002254 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002255 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002256 goto unlock;
2257 }
2258
2259 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002260
2261unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002262 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002263 return err;
2264}
2265
Marcel Holtmann1904a852015-01-11 13:50:44 -08002266static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002267{
2268 BT_DBG("status 0x%02x", status);
2269
2270 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2271}
2272
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002273static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002275{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002276 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002277 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002278 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002279 int err;
2280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002282
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002283 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002284 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2285 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002286
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002287 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002288
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002289 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002290 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2291 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002292 goto unlock;
2293 }
2294
2295 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002296 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2297 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002298 goto unlock;
2299 }
2300
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002301 hdev->major_class = cp->major;
2302 hdev->minor_class = cp->minor;
2303
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002304 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002305 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2306 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002307 goto unlock;
2308 }
2309
Johan Hedberg890ea892013-03-15 17:06:52 -05002310 hci_req_init(&req, hdev);
2311
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002312 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002313 hci_dev_unlock(hdev);
2314 cancel_delayed_work_sync(&hdev->service_cache);
2315 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002316 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002317 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002318
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002319 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002320
Johan Hedberg92da6092013-03-15 17:06:55 -05002321 err = hci_req_run(&req, set_class_complete);
2322 if (err < 0) {
2323 if (err != -ENODATA)
2324 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002325
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002326 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2327 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002328 goto unlock;
2329 }
2330
2331 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002332 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002333 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002334 goto unlock;
2335 }
2336
2337 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002338
Johan Hedbergb5235a62012-02-21 14:32:24 +02002339unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002340 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002341 return err;
2342}
2343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002344static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002345 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002346{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002347 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002348 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2349 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002350 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002351 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002352 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002354 BT_DBG("request for %s", hdev->name);
2355
2356 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002357 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2358 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002359
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002360 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002361 if (key_count > max_key_count) {
2362 BT_ERR("load_link_keys: too big key_count value %u",
2363 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002364 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2365 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002366 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002367
Johan Hedberg86742e12011-11-07 23:13:38 +02002368 expected_len = sizeof(*cp) + key_count *
2369 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002370 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002371 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002372 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002373 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2374 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002375 }
2376
Johan Hedberg4ae14302013-01-20 14:27:13 +02002377 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002378 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2379 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002381 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002382 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002383
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002384 for (i = 0; i < key_count; i++) {
2385 struct mgmt_link_key_info *key = &cp->keys[i];
2386
Marcel Holtmann8e991132014-01-10 02:07:25 -08002387 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002388 return mgmt_cmd_status(sk, hdev->id,
2389 MGMT_OP_LOAD_LINK_KEYS,
2390 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002391 }
2392
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002393 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002394
2395 hci_link_keys_clear(hdev);
2396
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002397 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002398 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002399 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002400 changed = hci_dev_test_and_clear_flag(hdev,
2401 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002402
2403 if (changed)
2404 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002405
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002406 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002407 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002408
Johan Hedberg58e92932014-06-24 14:00:26 +03002409 /* Always ignore debug keys and require a new pairing if
2410 * the user wants to use them.
2411 */
2412 if (key->type == HCI_LK_DEBUG_COMBINATION)
2413 continue;
2414
Johan Hedberg7652ff62014-06-24 13:15:49 +03002415 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2416 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002417 }
2418
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002419 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002420
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002421 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002422
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002423 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002424}
2425
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002426static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002427 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002428{
2429 struct mgmt_ev_device_unpaired ev;
2430
2431 bacpy(&ev.addr.bdaddr, bdaddr);
2432 ev.addr.type = addr_type;
2433
2434 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002436}
2437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002438static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002439 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002440{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002441 struct mgmt_cp_unpair_device *cp = data;
2442 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002443 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002444 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002445 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002446 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002447 int err;
2448
Johan Hedberga8a1d192011-11-10 15:54:38 +02002449 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002450 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2451 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002452
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002453 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002454 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2455 MGMT_STATUS_INVALID_PARAMS,
2456 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002457
Johan Hedberg118da702013-01-20 14:27:20 +02002458 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002459 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2460 MGMT_STATUS_INVALID_PARAMS,
2461 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002462
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002463 hci_dev_lock(hdev);
2464
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002465 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002466 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2467 MGMT_STATUS_NOT_POWERED, &rp,
2468 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002469 goto unlock;
2470 }
2471
Johan Hedberge0b2b272014-02-18 17:14:31 +02002472 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002473 /* If disconnection is requested, then look up the
2474 * connection. If the remote device is connected, it
2475 * will be later used to terminate the link.
2476 *
2477 * Setting it to NULL explicitly will cause no
2478 * termination of the link.
2479 */
2480 if (cp->disconnect)
2481 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2482 &cp->addr.bdaddr);
2483 else
2484 conn = NULL;
2485
Johan Hedberg124f6e32012-02-09 13:50:12 +02002486 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002487 if (err < 0) {
2488 err = mgmt_cmd_complete(sk, hdev->id,
2489 MGMT_OP_UNPAIR_DEVICE,
2490 MGMT_STATUS_NOT_PAIRED, &rp,
2491 sizeof(rp));
2492 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002493 }
2494
Johan Hedbergec182f02015-10-21 18:03:03 +03002495 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002496 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002497
Johan Hedbergec182f02015-10-21 18:03:03 +03002498 /* LE address type */
2499 addr_type = le_addr_type(cp->addr.type);
2500
2501 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2502
2503 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002504 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002505 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2506 MGMT_STATUS_NOT_PAIRED, &rp,
2507 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002508 goto unlock;
2509 }
2510
Johan Hedbergec182f02015-10-21 18:03:03 +03002511 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2512 if (!conn) {
2513 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2514 goto done;
2515 }
2516
Johan Hedbergc81d5552015-10-22 09:38:35 +03002517 /* Abort any ongoing SMP pairing */
2518 smp_cancel_pairing(conn);
2519
Johan Hedbergec182f02015-10-21 18:03:03 +03002520 /* Defer clearing up the connection parameters until closing to
2521 * give a chance of keeping them if a repairing happens.
2522 */
2523 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2524
Johan Hedbergfc643612015-10-22 09:38:31 +03002525 /* Disable auto-connection parameters if present */
2526 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2527 if (params) {
2528 if (params->explicit_connect)
2529 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2530 else
2531 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2532 }
2533
Johan Hedbergec182f02015-10-21 18:03:03 +03002534 /* If disconnection is not requested, then clear the connection
2535 * variable so that the link is not terminated.
2536 */
2537 if (!cp->disconnect)
2538 conn = NULL;
2539
2540done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002541 /* If the connection variable is set, then termination of the
2542 * link is requested.
2543 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002544 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002545 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2546 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002547 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002548 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002549 }
2550
Johan Hedberg124f6e32012-02-09 13:50:12 +02002551 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002552 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002553 if (!cmd) {
2554 err = -ENOMEM;
2555 goto unlock;
2556 }
2557
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002558 cmd->cmd_complete = addr_cmd_complete;
2559
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002560 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002561 if (err < 0)
2562 mgmt_pending_remove(cmd);
2563
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002564unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002565 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002566 return err;
2567}
2568
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002569static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002570 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002571{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002572 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002573 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002574 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002575 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002576 int err;
2577
2578 BT_DBG("");
2579
Johan Hedberg06a63b12013-01-20 14:27:21 +02002580 memset(&rp, 0, sizeof(rp));
2581 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2582 rp.addr.type = cp->addr.type;
2583
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002584 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002585 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2586 MGMT_STATUS_INVALID_PARAMS,
2587 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002588
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002589 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002590
2591 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002592 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2593 MGMT_STATUS_NOT_POWERED, &rp,
2594 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002595 goto failed;
2596 }
2597
Johan Hedberg333ae952015-03-17 13:48:47 +02002598 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002599 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2600 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002601 goto failed;
2602 }
2603
Andre Guedes591f47f2012-04-24 21:02:49 -03002604 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002605 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2606 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002607 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002608 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2609 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002610
Vishal Agarwalf9607272012-06-13 05:32:43 +05302611 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002612 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2613 MGMT_STATUS_NOT_CONNECTED, &rp,
2614 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002615 goto failed;
2616 }
2617
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002618 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002619 if (!cmd) {
2620 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002621 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002622 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002623
Johan Hedbergf5818c22014-12-05 13:36:02 +02002624 cmd->cmd_complete = generic_cmd_complete;
2625
Johan Hedberge3f2f922014-08-18 20:33:33 +03002626 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002627 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002628 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002629
2630failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002631 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002632 return err;
2633}
2634
Andre Guedes57c14772012-04-24 21:02:50 -03002635static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002636{
2637 switch (link_type) {
2638 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002639 switch (addr_type) {
2640 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002641 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002642
Johan Hedberg48264f02011-11-09 13:58:58 +02002643 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002644 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002645 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002646 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002647
Johan Hedberg4c659c32011-11-07 23:13:39 +02002648 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002649 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002650 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002651 }
2652}
2653
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2655 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002656{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002657 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002658 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002659 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002660 int err;
2661 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002662
2663 BT_DBG("");
2664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002665 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002666
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002667 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002668 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2669 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002670 goto unlock;
2671 }
2672
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002673 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002674 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2675 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002676 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002677 }
2678
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002679 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002680 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002681 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002682 err = -ENOMEM;
2683 goto unlock;
2684 }
2685
Johan Hedberg2784eb42011-01-21 13:56:35 +02002686 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002687 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002688 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2689 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002690 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002691 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002692 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002693 continue;
2694 i++;
2695 }
2696
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002697 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002698
Johan Hedberg4c659c32011-11-07 23:13:39 +02002699 /* Recalculate length in case of filtered SCO connections, etc */
2700 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002701
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002702 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2703 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002704
Johan Hedberga38528f2011-01-22 06:46:43 +02002705 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002706
2707unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002708 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002709 return err;
2710}
2711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002712static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002713 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002714{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002715 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002716 int err;
2717
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002718 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002719 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002720 if (!cmd)
2721 return -ENOMEM;
2722
Johan Hedbergd8457692012-02-17 14:24:57 +02002723 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002724 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002725 if (err < 0)
2726 mgmt_pending_remove(cmd);
2727
2728 return err;
2729}
2730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002731static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002733{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002734 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002735 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002736 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002737 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002738 int err;
2739
2740 BT_DBG("");
2741
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002742 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002743
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002744 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002745 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2746 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002747 goto failed;
2748 }
2749
Johan Hedbergd8457692012-02-17 14:24:57 +02002750 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002751 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002752 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2753 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002754 goto failed;
2755 }
2756
2757 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002758 struct mgmt_cp_pin_code_neg_reply ncp;
2759
2760 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002761
2762 BT_ERR("PIN code is not 16 bytes long");
2763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002764 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002765 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002766 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2767 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002768
2769 goto failed;
2770 }
2771
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002772 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002773 if (!cmd) {
2774 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002775 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002776 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002777
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002778 cmd->cmd_complete = addr_cmd_complete;
2779
Johan Hedbergd8457692012-02-17 14:24:57 +02002780 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002781 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002782 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002783
2784 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2785 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002786 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002787
2788failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002789 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002790 return err;
2791}
2792
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002793static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2794 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002795{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002796 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002797
2798 BT_DBG("");
2799
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002800 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002801 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2802 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002804 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002805
2806 hdev->io_capability = cp->io_capability;
2807
2808 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002809 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002811 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002812
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002813 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2814 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002815}
2816
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002817static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002818{
2819 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002820 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002821
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002822 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002823 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2824 continue;
2825
Johan Hedberge9a416b2011-02-19 12:05:56 -03002826 if (cmd->user_data != conn)
2827 continue;
2828
2829 return cmd;
2830 }
2831
2832 return NULL;
2833}
2834
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002835static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002836{
2837 struct mgmt_rp_pair_device rp;
2838 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002839 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002840
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002841 bacpy(&rp.addr.bdaddr, &conn->dst);
2842 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002843
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002844 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2845 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002846
2847 /* So we don't get further callbacks for this connection */
2848 conn->connect_cfm_cb = NULL;
2849 conn->security_cfm_cb = NULL;
2850 conn->disconn_cfm_cb = NULL;
2851
David Herrmann76a68ba2013-04-06 20:28:37 +02002852 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002853
2854 /* The device is paired so there is no need to remove
2855 * its connection parameters anymore.
2856 */
2857 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002858
2859 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002860
2861 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002862}
2863
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002864void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2865{
2866 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002867 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002868
2869 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002870 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002871 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002872 mgmt_pending_remove(cmd);
2873 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002874}
2875
Johan Hedberge9a416b2011-02-19 12:05:56 -03002876static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2877{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002878 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002879
2880 BT_DBG("status %u", status);
2881
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002882 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002883 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002884 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002885 return;
2886 }
2887
2888 cmd->cmd_complete(cmd, mgmt_status(status));
2889 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002890}
2891
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002892static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302893{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002894 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302895
2896 BT_DBG("status %u", status);
2897
2898 if (!status)
2899 return;
2900
2901 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002902 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302903 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002904 return;
2905 }
2906
2907 cmd->cmd_complete(cmd, mgmt_status(status));
2908 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302909}
2910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002911static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002912 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002913{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002914 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002915 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002916 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002917 u8 sec_level, auth_type;
2918 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002919 int err;
2920
2921 BT_DBG("");
2922
Szymon Jancf950a30e2013-01-18 12:48:07 +01002923 memset(&rp, 0, sizeof(rp));
2924 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2925 rp.addr.type = cp->addr.type;
2926
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002927 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002928 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2929 MGMT_STATUS_INVALID_PARAMS,
2930 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002931
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002932 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002933 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2934 MGMT_STATUS_INVALID_PARAMS,
2935 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002936
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002937 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002938
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002939 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002940 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2941 MGMT_STATUS_NOT_POWERED, &rp,
2942 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002943 goto unlock;
2944 }
2945
Johan Hedberg55e76b32015-03-10 22:34:40 +02002946 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2947 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2948 MGMT_STATUS_ALREADY_PAIRED, &rp,
2949 sizeof(rp));
2950 goto unlock;
2951 }
2952
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002953 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002954 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002955
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002956 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002957 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2958 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002959 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002960 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002961 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002962
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002963 /* When pairing a new device, it is expected to remember
2964 * this device for future connections. Adding the connection
2965 * parameter information ahead of time allows tracking
2966 * of the slave preferred values and will speed up any
2967 * further connection establishment.
2968 *
2969 * If connection parameters already exist, then they
2970 * will be kept and this function does nothing.
2971 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002972 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2973
2974 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2975 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002976
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002977 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2978 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002979 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002980 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002981
Ville Tervo30e76272011-02-22 16:10:53 -03002982 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002983 int status;
2984
2985 if (PTR_ERR(conn) == -EBUSY)
2986 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002987 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2988 status = MGMT_STATUS_NOT_SUPPORTED;
2989 else if (PTR_ERR(conn) == -ECONNREFUSED)
2990 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002991 else
2992 status = MGMT_STATUS_CONNECT_FAILED;
2993
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002994 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2995 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002996 goto unlock;
2997 }
2998
2999 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003000 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003001 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3002 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003003 goto unlock;
3004 }
3005
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003006 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003007 if (!cmd) {
3008 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003009 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003010 goto unlock;
3011 }
3012
Johan Hedberg04ab2742014-12-05 13:36:04 +02003013 cmd->cmd_complete = pairing_complete;
3014
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003015 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003016 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003017 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003018 conn->security_cfm_cb = pairing_complete_cb;
3019 conn->disconn_cfm_cb = pairing_complete_cb;
3020 } else {
3021 conn->connect_cfm_cb = le_pairing_complete_cb;
3022 conn->security_cfm_cb = le_pairing_complete_cb;
3023 conn->disconn_cfm_cb = le_pairing_complete_cb;
3024 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003025
Johan Hedberge9a416b2011-02-19 12:05:56 -03003026 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003027 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003028
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003029 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003030 hci_conn_security(conn, sec_level, auth_type, true)) {
3031 cmd->cmd_complete(cmd, 0);
3032 mgmt_pending_remove(cmd);
3033 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003034
3035 err = 0;
3036
3037unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003038 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003039 return err;
3040}
3041
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003042static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3043 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003044{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003045 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003046 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003047 struct hci_conn *conn;
3048 int err;
3049
3050 BT_DBG("");
3051
Johan Hedberg28424702012-02-02 04:02:29 +02003052 hci_dev_lock(hdev);
3053
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003054 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003055 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3056 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003057 goto unlock;
3058 }
3059
Johan Hedberg333ae952015-03-17 13:48:47 +02003060 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003061 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003062 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3063 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003064 goto unlock;
3065 }
3066
3067 conn = cmd->user_data;
3068
3069 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003070 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3071 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003072 goto unlock;
3073 }
3074
Johan Hedberga511b352014-12-11 21:45:45 +02003075 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3076 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003077
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003078 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3079 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003080unlock:
3081 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003082 return err;
3083}
3084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003085static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003086 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003088{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003089 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003090 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003091 int err;
3092
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003093 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003094
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003095 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003096 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3097 MGMT_STATUS_NOT_POWERED, addr,
3098 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003099 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003100 }
3101
Johan Hedberg1707c602013-03-15 17:07:15 -05003102 if (addr->type == BDADDR_BREDR)
3103 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003104 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003105 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3106 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003107
Johan Hedberg272d90d2012-02-09 15:26:12 +02003108 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003109 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3110 MGMT_STATUS_NOT_CONNECTED, addr,
3111 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003112 goto done;
3113 }
3114
Johan Hedberg1707c602013-03-15 17:07:15 -05003115 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003116 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003117 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003118 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3119 MGMT_STATUS_SUCCESS, addr,
3120 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003121 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003122 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3123 MGMT_STATUS_FAILED, addr,
3124 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003125
Brian Gix47c15e22011-11-16 13:53:14 -08003126 goto done;
3127 }
3128
Johan Hedberg1707c602013-03-15 17:07:15 -05003129 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003130 if (!cmd) {
3131 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003132 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003133 }
3134
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003135 cmd->cmd_complete = addr_cmd_complete;
3136
Brian Gix0df4c182011-11-16 13:53:13 -08003137 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003138 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3139 struct hci_cp_user_passkey_reply cp;
3140
Johan Hedberg1707c602013-03-15 17:07:15 -05003141 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003142 cp.passkey = passkey;
3143 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3144 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003145 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3146 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003147
Johan Hedberga664b5b2011-02-19 12:06:02 -03003148 if (err < 0)
3149 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003150
Brian Gix0df4c182011-11-16 13:53:13 -08003151done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003152 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003153 return err;
3154}
3155
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303156static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3157 void *data, u16 len)
3158{
3159 struct mgmt_cp_pin_code_neg_reply *cp = data;
3160
3161 BT_DBG("");
3162
Johan Hedberg1707c602013-03-15 17:07:15 -05003163 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303164 MGMT_OP_PIN_CODE_NEG_REPLY,
3165 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3166}
3167
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003168static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3169 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003170{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003171 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003172
3173 BT_DBG("");
3174
3175 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003176 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3177 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003178
Johan Hedberg1707c602013-03-15 17:07:15 -05003179 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 MGMT_OP_USER_CONFIRM_REPLY,
3181 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003182}
3183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003184static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003185 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003186{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003187 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003188
3189 BT_DBG("");
3190
Johan Hedberg1707c602013-03-15 17:07:15 -05003191 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3193 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003194}
3195
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003196static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3197 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003198{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003199 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003200
3201 BT_DBG("");
3202
Johan Hedberg1707c602013-03-15 17:07:15 -05003203 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003204 MGMT_OP_USER_PASSKEY_REPLY,
3205 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003206}
3207
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003208static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003209 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003210{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003211 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003212
3213 BT_DBG("");
3214
Johan Hedberg1707c602013-03-15 17:07:15 -05003215 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3217 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003218}
3219
Johan Hedberg13928972013-03-15 17:07:00 -05003220static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003221{
Johan Hedberg13928972013-03-15 17:07:00 -05003222 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003223 struct hci_cp_write_local_name cp;
3224
Johan Hedberg13928972013-03-15 17:07:00 -05003225 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003226
Johan Hedberg890ea892013-03-15 17:06:52 -05003227 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003228}
3229
Marcel Holtmann1904a852015-01-11 13:50:44 -08003230static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003231{
3232 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003233 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003234
3235 BT_DBG("status 0x%02x", status);
3236
3237 hci_dev_lock(hdev);
3238
Johan Hedberg333ae952015-03-17 13:48:47 +02003239 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003240 if (!cmd)
3241 goto unlock;
3242
3243 cp = cmd->param;
3244
3245 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003246 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3247 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003248 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003249 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3250 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003251
3252 mgmt_pending_remove(cmd);
3253
3254unlock:
3255 hci_dev_unlock(hdev);
3256}
3257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003258static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003259 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003260{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003261 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003262 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003263 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003264 int err;
3265
3266 BT_DBG("");
3267
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003268 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003269
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003270 /* If the old values are the same as the new ones just return a
3271 * direct command complete event.
3272 */
3273 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3274 !memcmp(hdev->short_name, cp->short_name,
3275 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003276 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3277 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003278 goto failed;
3279 }
3280
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003281 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003282
Johan Hedbergb5235a62012-02-21 14:32:24 +02003283 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003284 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003285
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003286 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3287 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003288 if (err < 0)
3289 goto failed;
3290
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003291 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3292 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003293
Johan Hedbergb5235a62012-02-21 14:32:24 +02003294 goto failed;
3295 }
3296
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003297 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003298 if (!cmd) {
3299 err = -ENOMEM;
3300 goto failed;
3301 }
3302
Johan Hedberg13928972013-03-15 17:07:00 -05003303 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3304
Johan Hedberg890ea892013-03-15 17:06:52 -05003305 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003306
3307 if (lmp_bredr_capable(hdev)) {
3308 update_name(&req);
3309 update_eir(&req);
3310 }
3311
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003312 /* The name is stored in the scan response data and so
3313 * no need to udpate the advertising data here.
3314 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003315 if (lmp_le_capable(hdev))
Johan Hedbergf2252572015-11-18 12:49:20 +02003316 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Johan Hedberg3f985052013-03-15 17:07:02 -05003317
Johan Hedberg13928972013-03-15 17:07:00 -05003318 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003319 if (err < 0)
3320 mgmt_pending_remove(cmd);
3321
3322failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003323 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003324 return err;
3325}
3326
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003327static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3328 u16 opcode, struct sk_buff *skb)
3329{
3330 struct mgmt_rp_read_local_oob_data mgmt_rp;
3331 size_t rp_size = sizeof(mgmt_rp);
3332 struct mgmt_pending_cmd *cmd;
3333
3334 BT_DBG("%s status %u", hdev->name, status);
3335
3336 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3337 if (!cmd)
3338 return;
3339
3340 if (status || !skb) {
3341 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3342 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3343 goto remove;
3344 }
3345
3346 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3347
3348 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3349 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3350
3351 if (skb->len < sizeof(*rp)) {
3352 mgmt_cmd_status(cmd->sk, hdev->id,
3353 MGMT_OP_READ_LOCAL_OOB_DATA,
3354 MGMT_STATUS_FAILED);
3355 goto remove;
3356 }
3357
3358 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3359 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3360
3361 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3362 } else {
3363 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3364
3365 if (skb->len < sizeof(*rp)) {
3366 mgmt_cmd_status(cmd->sk, hdev->id,
3367 MGMT_OP_READ_LOCAL_OOB_DATA,
3368 MGMT_STATUS_FAILED);
3369 goto remove;
3370 }
3371
3372 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3373 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3374
3375 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3376 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3377 }
3378
3379 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3380 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3381
3382remove:
3383 mgmt_pending_remove(cmd);
3384}
3385
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003386static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003387 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003388{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003389 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003390 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003391 int err;
3392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003393 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003395 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003396
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003397 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003398 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3399 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003400 goto unlock;
3401 }
3402
Andre Guedes9a1a1992012-07-24 15:03:48 -03003403 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003404 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3405 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003406 goto unlock;
3407 }
3408
Johan Hedberg333ae952015-03-17 13:48:47 +02003409 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003410 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3411 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003412 goto unlock;
3413 }
3414
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003415 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003416 if (!cmd) {
3417 err = -ENOMEM;
3418 goto unlock;
3419 }
3420
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003421 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003422
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003423 if (bredr_sc_enabled(hdev))
3424 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3425 else
3426 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3427
3428 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003429 if (err < 0)
3430 mgmt_pending_remove(cmd);
3431
3432unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003433 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003434 return err;
3435}
3436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003437static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003438 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003439{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003440 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003441 int err;
3442
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003443 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003444
Johan Hedberg5d57e792015-01-23 10:10:38 +02003445 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003446 return mgmt_cmd_complete(sk, hdev->id,
3447 MGMT_OP_ADD_REMOTE_OOB_DATA,
3448 MGMT_STATUS_INVALID_PARAMS,
3449 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003450
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003451 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003452
Marcel Holtmannec109112014-01-10 02:07:30 -08003453 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3454 struct mgmt_cp_add_remote_oob_data *cp = data;
3455 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003456
Johan Hedbergc19a4952014-11-17 20:52:19 +02003457 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003458 err = mgmt_cmd_complete(sk, hdev->id,
3459 MGMT_OP_ADD_REMOTE_OOB_DATA,
3460 MGMT_STATUS_INVALID_PARAMS,
3461 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003462 goto unlock;
3463 }
3464
Marcel Holtmannec109112014-01-10 02:07:30 -08003465 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003466 cp->addr.type, cp->hash,
3467 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003468 if (err < 0)
3469 status = MGMT_STATUS_FAILED;
3470 else
3471 status = MGMT_STATUS_SUCCESS;
3472
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003473 err = mgmt_cmd_complete(sk, hdev->id,
3474 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3475 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003476 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3477 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003478 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003479 u8 status;
3480
Johan Hedberg86df9202014-10-26 20:52:27 +01003481 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003482 /* Enforce zero-valued 192-bit parameters as
3483 * long as legacy SMP OOB isn't implemented.
3484 */
3485 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3486 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003487 err = mgmt_cmd_complete(sk, hdev->id,
3488 MGMT_OP_ADD_REMOTE_OOB_DATA,
3489 MGMT_STATUS_INVALID_PARAMS,
3490 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003491 goto unlock;
3492 }
3493
Johan Hedberg86df9202014-10-26 20:52:27 +01003494 rand192 = NULL;
3495 hash192 = NULL;
3496 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003497 /* In case one of the P-192 values is set to zero,
3498 * then just disable OOB data for P-192.
3499 */
3500 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3501 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3502 rand192 = NULL;
3503 hash192 = NULL;
3504 } else {
3505 rand192 = cp->rand192;
3506 hash192 = cp->hash192;
3507 }
3508 }
3509
3510 /* In case one of the P-256 values is set to zero, then just
3511 * disable OOB data for P-256.
3512 */
3513 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3514 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3515 rand256 = NULL;
3516 hash256 = NULL;
3517 } else {
3518 rand256 = cp->rand256;
3519 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003520 }
3521
Johan Hedberg81328d52014-10-26 20:33:47 +01003522 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003523 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003524 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003525 if (err < 0)
3526 status = MGMT_STATUS_FAILED;
3527 else
3528 status = MGMT_STATUS_SUCCESS;
3529
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003530 err = mgmt_cmd_complete(sk, hdev->id,
3531 MGMT_OP_ADD_REMOTE_OOB_DATA,
3532 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003533 } else {
3534 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003535 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3536 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003537 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003538
Johan Hedbergc19a4952014-11-17 20:52:19 +02003539unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003540 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003541 return err;
3542}
3543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003544static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003545 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003546{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003547 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003548 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003549 int err;
3550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003551 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003552
Johan Hedbergc19a4952014-11-17 20:52:19 +02003553 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003554 return mgmt_cmd_complete(sk, hdev->id,
3555 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3556 MGMT_STATUS_INVALID_PARAMS,
3557 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003559 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003560
Johan Hedbergeedbd582014-11-15 09:34:23 +02003561 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3562 hci_remote_oob_data_clear(hdev);
3563 status = MGMT_STATUS_SUCCESS;
3564 goto done;
3565 }
3566
Johan Hedberg6928a922014-10-26 20:46:09 +01003567 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003568 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003569 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003570 else
Szymon Janca6785be2012-12-13 15:11:21 +01003571 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003572
Johan Hedbergeedbd582014-11-15 09:34:23 +02003573done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003574 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3575 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003576
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003577 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003578 return err;
3579}
3580
Johan Hedberge68f0722015-11-11 08:30:30 +02003581void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003582{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003583 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003584
Andre Guedes7c307722013-04-30 15:29:28 -03003585 BT_DBG("status %d", status);
3586
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003587 hci_dev_lock(hdev);
3588
Johan Hedberg333ae952015-03-17 13:48:47 +02003589 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003590 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003591 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003592
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003593 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003594 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003595 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003596 }
3597
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003598 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003599}
3600
Johan Hedberg591752a2015-11-11 08:11:24 +02003601static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3602 uint8_t *mgmt_status)
3603{
3604 switch (type) {
3605 case DISCOV_TYPE_LE:
3606 *mgmt_status = mgmt_le_support(hdev);
3607 if (*mgmt_status)
3608 return false;
3609 break;
3610 case DISCOV_TYPE_INTERLEAVED:
3611 *mgmt_status = mgmt_le_support(hdev);
3612 if (*mgmt_status)
3613 return false;
3614 /* Intentional fall-through */
3615 case DISCOV_TYPE_BREDR:
3616 *mgmt_status = mgmt_bredr_support(hdev);
3617 if (*mgmt_status)
3618 return false;
3619 break;
3620 default:
3621 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3622 return false;
3623 }
3624
3625 return true;
3626}
3627
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003628static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003629 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003630{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003631 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003632 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003633 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003634 int err;
3635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003636 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003638 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003639
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003640 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003641 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3642 MGMT_STATUS_NOT_POWERED,
3643 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003644 goto failed;
3645 }
3646
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003647 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003648 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003649 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3650 MGMT_STATUS_BUSY, &cp->type,
3651 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003652 goto failed;
3653 }
3654
Johan Hedberg591752a2015-11-11 08:11:24 +02003655 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3656 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3657 status, &cp->type, sizeof(cp->type));
3658 goto failed;
3659 }
3660
Marcel Holtmann22078802014-12-05 11:45:22 +01003661 /* Clear the discovery filter first to free any previously
3662 * allocated memory for the UUID list.
3663 */
3664 hci_discovery_filter_clear(hdev);
3665
Andre Guedes4aab14e2012-02-17 20:39:36 -03003666 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003667 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003668
Johan Hedberge68f0722015-11-11 08:30:30 +02003669 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
3670 if (!cmd) {
3671 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003672 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003673 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003674
Johan Hedberge68f0722015-11-11 08:30:30 +02003675 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003676
3677 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003678 queue_work(hdev->req_workqueue, &hdev->discov_update);
3679 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003680
3681failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003682 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003683 return err;
3684}
3685
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003686static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3687 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003688{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003689 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3690 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003691}
3692
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003693static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3694 void *data, u16 len)
3695{
3696 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003697 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003698 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3699 u16 uuid_count, expected_len;
3700 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003701 int err;
3702
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003703 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003704
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003705 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003706
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003707 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003708 err = mgmt_cmd_complete(sk, hdev->id,
3709 MGMT_OP_START_SERVICE_DISCOVERY,
3710 MGMT_STATUS_NOT_POWERED,
3711 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003712 goto failed;
3713 }
3714
3715 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003716 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003717 err = mgmt_cmd_complete(sk, hdev->id,
3718 MGMT_OP_START_SERVICE_DISCOVERY,
3719 MGMT_STATUS_BUSY, &cp->type,
3720 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003721 goto failed;
3722 }
3723
3724 uuid_count = __le16_to_cpu(cp->uuid_count);
3725 if (uuid_count > max_uuid_count) {
3726 BT_ERR("service_discovery: too big uuid_count value %u",
3727 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003728 err = mgmt_cmd_complete(sk, hdev->id,
3729 MGMT_OP_START_SERVICE_DISCOVERY,
3730 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3731 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003732 goto failed;
3733 }
3734
3735 expected_len = sizeof(*cp) + uuid_count * 16;
3736 if (expected_len != len) {
3737 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3738 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003739 err = mgmt_cmd_complete(sk, hdev->id,
3740 MGMT_OP_START_SERVICE_DISCOVERY,
3741 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3742 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003743 goto failed;
3744 }
3745
Johan Hedberg591752a2015-11-11 08:11:24 +02003746 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3747 err = mgmt_cmd_complete(sk, hdev->id,
3748 MGMT_OP_START_SERVICE_DISCOVERY,
3749 status, &cp->type, sizeof(cp->type));
3750 goto failed;
3751 }
3752
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003753 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003754 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003755 if (!cmd) {
3756 err = -ENOMEM;
3757 goto failed;
3758 }
3759
Johan Hedberg2922a942014-12-05 13:36:06 +02003760 cmd->cmd_complete = service_discovery_cmd_complete;
3761
Marcel Holtmann22078802014-12-05 11:45:22 +01003762 /* Clear the discovery filter first to free any previously
3763 * allocated memory for the UUID list.
3764 */
3765 hci_discovery_filter_clear(hdev);
3766
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003767 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003768 hdev->discovery.type = cp->type;
3769 hdev->discovery.rssi = cp->rssi;
3770 hdev->discovery.uuid_count = uuid_count;
3771
3772 if (uuid_count > 0) {
3773 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3774 GFP_KERNEL);
3775 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003776 err = mgmt_cmd_complete(sk, hdev->id,
3777 MGMT_OP_START_SERVICE_DISCOVERY,
3778 MGMT_STATUS_FAILED,
3779 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003780 mgmt_pending_remove(cmd);
3781 goto failed;
3782 }
3783 }
3784
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003785 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003786 queue_work(hdev->req_workqueue, &hdev->discov_update);
3787 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003788
3789failed:
3790 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003791 return err;
3792}
3793
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003794void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003795{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003796 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003797
Andre Guedes0e05bba2013-04-30 15:29:33 -03003798 BT_DBG("status %d", status);
3799
3800 hci_dev_lock(hdev);
3801
Johan Hedberg333ae952015-03-17 13:48:47 +02003802 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003803 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003804 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003805 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003806 }
3807
Andre Guedes0e05bba2013-04-30 15:29:33 -03003808 hci_dev_unlock(hdev);
3809}
3810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003811static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003812 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003813{
Johan Hedbergd9306502012-02-20 23:25:18 +02003814 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003815 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003816 int err;
3817
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003818 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003819
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003820 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003821
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003822 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003823 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3824 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3825 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003826 goto unlock;
3827 }
3828
3829 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003830 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3831 MGMT_STATUS_INVALID_PARAMS,
3832 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003833 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003834 }
3835
Johan Hedberg2922a942014-12-05 13:36:06 +02003836 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003837 if (!cmd) {
3838 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003839 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003840 }
3841
Johan Hedberg2922a942014-12-05 13:36:06 +02003842 cmd->cmd_complete = generic_cmd_complete;
3843
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003844 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3845 queue_work(hdev->req_workqueue, &hdev->discov_update);
3846 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003847
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003848unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003849 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003850 return err;
3851}
3852
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003853static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003854 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003855{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003856 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003857 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003858 int err;
3859
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003860 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003861
Johan Hedberg561aafb2012-01-04 13:31:59 +02003862 hci_dev_lock(hdev);
3863
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003864 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003865 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3866 MGMT_STATUS_FAILED, &cp->addr,
3867 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003868 goto failed;
3869 }
3870
Johan Hedberga198e7b2012-02-17 14:27:06 +02003871 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003872 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003873 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3874 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3875 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003876 goto failed;
3877 }
3878
3879 if (cp->name_known) {
3880 e->name_state = NAME_KNOWN;
3881 list_del(&e->list);
3882 } else {
3883 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003884 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003885 }
3886
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003887 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3888 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003889
3890failed:
3891 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003892 return err;
3893}
3894
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003895static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003896 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003897{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003898 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003899 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003900 int err;
3901
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003902 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003903
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003904 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003905 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3906 MGMT_STATUS_INVALID_PARAMS,
3907 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003908
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003909 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003910
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003911 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3912 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003913 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003914 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003915 goto done;
3916 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003917
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003918 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3919 sk);
3920 status = MGMT_STATUS_SUCCESS;
3921
3922done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003923 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3924 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003925
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003926 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003927
3928 return err;
3929}
3930
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003931static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003932 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003933{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003934 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003935 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003936 int err;
3937
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003938 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003939
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003940 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003941 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3942 MGMT_STATUS_INVALID_PARAMS,
3943 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003944
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003945 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003946
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003947 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3948 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003949 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003950 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003951 goto done;
3952 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003953
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003954 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3955 sk);
3956 status = MGMT_STATUS_SUCCESS;
3957
3958done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003959 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3960 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003961
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003962 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003963
3964 return err;
3965}
3966
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003967static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3968 u16 len)
3969{
3970 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003971 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003972 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003973 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003974
3975 BT_DBG("%s", hdev->name);
3976
Szymon Jancc72d4b82012-03-16 16:02:57 +01003977 source = __le16_to_cpu(cp->source);
3978
3979 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003980 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3981 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003982
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003983 hci_dev_lock(hdev);
3984
Szymon Jancc72d4b82012-03-16 16:02:57 +01003985 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003986 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3987 hdev->devid_product = __le16_to_cpu(cp->product);
3988 hdev->devid_version = __le16_to_cpu(cp->version);
3989
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003990 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3991 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003992
Johan Hedberg890ea892013-03-15 17:06:52 -05003993 hci_req_init(&req, hdev);
3994 update_eir(&req);
3995 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003996
3997 hci_dev_unlock(hdev);
3998
3999 return err;
4000}
4001
Arman Uguray24b4f382015-03-23 15:57:12 -07004002static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4003 u16 opcode)
4004{
4005 BT_DBG("status %d", status);
4006}
4007
Marcel Holtmann1904a852015-01-11 13:50:44 -08004008static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4009 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004010{
4011 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004012 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02004013 u8 instance;
4014 struct adv_info *adv_instance;
4015 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03004016
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304017 hci_dev_lock(hdev);
4018
Johan Hedberg4375f102013-09-25 13:26:10 +03004019 if (status) {
4020 u8 mgmt_err = mgmt_status(status);
4021
4022 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4023 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304024 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004025 }
4026
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004027 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004028 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004029 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004030 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004031
Johan Hedberg4375f102013-09-25 13:26:10 +03004032 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4033 &match);
4034
4035 new_settings(hdev, match.sk);
4036
4037 if (match.sk)
4038 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304039
Arman Uguray24b4f382015-03-23 15:57:12 -07004040 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02004041 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07004042 */
4043 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02004044 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
4045 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07004046 goto unlock;
4047
Florian Grandel7816b822015-06-18 03:16:45 +02004048 instance = hdev->cur_adv_instance;
4049 if (!instance) {
4050 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4051 struct adv_info, list);
4052 if (!adv_instance)
4053 goto unlock;
4054
4055 instance = adv_instance->instance;
4056 }
4057
Arman Uguray24b4f382015-03-23 15:57:12 -07004058 hci_req_init(&req, hdev);
4059
Johan Hedbergf2252572015-11-18 12:49:20 +02004060 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07004061
Florian Grandel7816b822015-06-18 03:16:45 +02004062 if (!err)
4063 err = hci_req_run(&req, enable_advertising_instance);
4064
4065 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07004066 BT_ERR("Failed to re-configure advertising");
4067
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304068unlock:
4069 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004070}
4071
Marcel Holtmann21b51872013-10-10 09:47:53 -07004072static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4073 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004074{
4075 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004076 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004077 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004078 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004079 int err;
4080
4081 BT_DBG("request for %s", hdev->name);
4082
Johan Hedberge6fe7982013-10-02 15:45:22 +03004083 status = mgmt_le_support(hdev);
4084 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004085 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4086 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004087
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004088 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004089 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4090 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004091
4092 hci_dev_lock(hdev);
4093
4094 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004095
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004096 /* The following conditions are ones which mean that we should
4097 * not do any HCI communication but directly send a mgmt
4098 * response to user space (after toggling the flag if
4099 * necessary).
4100 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004101 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004102 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4103 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004104 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004105 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004106 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004107 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004108
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004109 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004110 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004111 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004112 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004113 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004114 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004115 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004116 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004117 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004118 }
4119
4120 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4121 if (err < 0)
4122 goto unlock;
4123
4124 if (changed)
4125 err = new_settings(hdev, sk);
4126
4127 goto unlock;
4128 }
4129
Johan Hedberg333ae952015-03-17 13:48:47 +02004130 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4131 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004132 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4133 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004134 goto unlock;
4135 }
4136
4137 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4138 if (!cmd) {
4139 err = -ENOMEM;
4140 goto unlock;
4141 }
4142
4143 hci_req_init(&req, hdev);
4144
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004145 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004146 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004147 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004148 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004149
Florian Grandel7816b822015-06-18 03:16:45 +02004150 cancel_adv_timeout(hdev);
4151
Arman Uguray24b4f382015-03-23 15:57:12 -07004152 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004153 /* Switch to instance "0" for the Set Advertising setting.
4154 * We cannot use update_[adv|scan_rsp]_data() here as the
4155 * HCI_ADVERTISING flag is not yet set.
4156 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004157 __hci_req_update_adv_data(&req, 0x00);
4158 __hci_req_update_scan_rsp_data(&req, 0x00);
4159 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004160 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004161 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004162 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004163
4164 err = hci_req_run(&req, set_advertising_complete);
4165 if (err < 0)
4166 mgmt_pending_remove(cmd);
4167
4168unlock:
4169 hci_dev_unlock(hdev);
4170 return err;
4171}
4172
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004173static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4174 void *data, u16 len)
4175{
4176 struct mgmt_cp_set_static_address *cp = data;
4177 int err;
4178
4179 BT_DBG("%s", hdev->name);
4180
Marcel Holtmann62af4442013-10-02 22:10:32 -07004181 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004182 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4183 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004184
4185 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004186 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4187 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004188
4189 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4190 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004191 return mgmt_cmd_status(sk, hdev->id,
4192 MGMT_OP_SET_STATIC_ADDRESS,
4193 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004194
4195 /* Two most significant bits shall be set */
4196 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004197 return mgmt_cmd_status(sk, hdev->id,
4198 MGMT_OP_SET_STATIC_ADDRESS,
4199 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004200 }
4201
4202 hci_dev_lock(hdev);
4203
4204 bacpy(&hdev->static_addr, &cp->bdaddr);
4205
Marcel Holtmann93690c22015-03-06 10:11:21 -08004206 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4207 if (err < 0)
4208 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004209
Marcel Holtmann93690c22015-03-06 10:11:21 -08004210 err = new_settings(hdev, sk);
4211
4212unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004213 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004214 return err;
4215}
4216
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004217static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4218 void *data, u16 len)
4219{
4220 struct mgmt_cp_set_scan_params *cp = data;
4221 __u16 interval, window;
4222 int err;
4223
4224 BT_DBG("%s", hdev->name);
4225
4226 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004227 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4228 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004229
4230 interval = __le16_to_cpu(cp->interval);
4231
4232 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004233 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4234 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004235
4236 window = __le16_to_cpu(cp->window);
4237
4238 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004239 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4240 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004241
Marcel Holtmann899e1072013-10-14 09:55:32 -07004242 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004243 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4244 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004245
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004246 hci_dev_lock(hdev);
4247
4248 hdev->le_scan_interval = interval;
4249 hdev->le_scan_window = window;
4250
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004251 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4252 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004253
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004254 /* If background scan is running, restart it so new parameters are
4255 * loaded.
4256 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004257 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004258 hdev->discovery.state == DISCOVERY_STOPPED) {
4259 struct hci_request req;
4260
4261 hci_req_init(&req, hdev);
4262
4263 hci_req_add_le_scan_disable(&req);
4264 hci_req_add_le_passive_scan(&req);
4265
4266 hci_req_run(&req, NULL);
4267 }
4268
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004269 hci_dev_unlock(hdev);
4270
4271 return err;
4272}
4273
Marcel Holtmann1904a852015-01-11 13:50:44 -08004274static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4275 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004276{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004277 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004278
4279 BT_DBG("status 0x%02x", status);
4280
4281 hci_dev_lock(hdev);
4282
Johan Hedberg333ae952015-03-17 13:48:47 +02004283 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004284 if (!cmd)
4285 goto unlock;
4286
4287 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004288 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4289 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004290 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004291 struct mgmt_mode *cp = cmd->param;
4292
4293 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004294 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004295 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004296 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004297
Johan Hedberg33e38b32013-03-15 17:07:05 -05004298 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4299 new_settings(hdev, cmd->sk);
4300 }
4301
4302 mgmt_pending_remove(cmd);
4303
4304unlock:
4305 hci_dev_unlock(hdev);
4306}
4307
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004308static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004309 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004310{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004311 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004312 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004313 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004314 int err;
4315
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004316 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004317
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004318 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004319 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004320 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4321 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004322
Johan Hedberga7e80f22013-01-09 16:05:19 +02004323 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004324 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4325 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004326
Antti Julkuf6422ec2011-06-22 13:11:56 +03004327 hci_dev_lock(hdev);
4328
Johan Hedberg333ae952015-03-17 13:48:47 +02004329 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004330 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4331 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004332 goto unlock;
4333 }
4334
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004335 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004336 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4337 hdev);
4338 goto unlock;
4339 }
4340
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004341 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004342 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004343 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4344 hdev);
4345 new_settings(hdev, sk);
4346 goto unlock;
4347 }
4348
Johan Hedberg33e38b32013-03-15 17:07:05 -05004349 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4350 data, len);
4351 if (!cmd) {
4352 err = -ENOMEM;
4353 goto unlock;
4354 }
4355
4356 hci_req_init(&req, hdev);
4357
Johan Hedberg406d7802013-03-15 17:07:09 -05004358 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004359
4360 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004361 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004362 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4363 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004364 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004365 }
4366
Johan Hedberg33e38b32013-03-15 17:07:05 -05004367unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004368 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004369
Antti Julkuf6422ec2011-06-22 13:11:56 +03004370 return err;
4371}
4372
Marcel Holtmann1904a852015-01-11 13:50:44 -08004373static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004374{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004375 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004376
4377 BT_DBG("status 0x%02x", status);
4378
4379 hci_dev_lock(hdev);
4380
Johan Hedberg333ae952015-03-17 13:48:47 +02004381 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004382 if (!cmd)
4383 goto unlock;
4384
4385 if (status) {
4386 u8 mgmt_err = mgmt_status(status);
4387
4388 /* We need to restore the flag if related HCI commands
4389 * failed.
4390 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004391 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004392
Johan Hedberga69e8372015-03-06 21:08:53 +02004393 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004394 } else {
4395 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4396 new_settings(hdev, cmd->sk);
4397 }
4398
4399 mgmt_pending_remove(cmd);
4400
4401unlock:
4402 hci_dev_unlock(hdev);
4403}
4404
4405static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4406{
4407 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004408 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004409 struct hci_request req;
4410 int err;
4411
4412 BT_DBG("request for %s", hdev->name);
4413
4414 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004415 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4416 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004417
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004418 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004419 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4420 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004421
4422 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004423 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004425
4426 hci_dev_lock(hdev);
4427
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004428 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004429 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4430 goto unlock;
4431 }
4432
4433 if (!hdev_is_powered(hdev)) {
4434 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004435 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4436 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4437 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4438 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4439 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004440 }
4441
Marcel Holtmannce05d602015-03-13 02:11:03 -07004442 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004443
4444 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4445 if (err < 0)
4446 goto unlock;
4447
4448 err = new_settings(hdev, sk);
4449 goto unlock;
4450 }
4451
4452 /* Reject disabling when powered on */
4453 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004454 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4455 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004456 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004457 } else {
4458 /* When configuring a dual-mode controller to operate
4459 * with LE only and using a static address, then switching
4460 * BR/EDR back on is not allowed.
4461 *
4462 * Dual-mode controllers shall operate with the public
4463 * address as its identity address for BR/EDR and LE. So
4464 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004465 *
4466 * The same restrictions applies when secure connections
4467 * has been enabled. For BR/EDR this is a controller feature
4468 * while for LE it is a host stack feature. This means that
4469 * switching BR/EDR back on when secure connections has been
4470 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004471 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004472 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004473 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004474 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004475 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4476 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004477 goto unlock;
4478 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004479 }
4480
Johan Hedberg333ae952015-03-17 13:48:47 +02004481 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004482 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4483 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004484 goto unlock;
4485 }
4486
4487 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4488 if (!cmd) {
4489 err = -ENOMEM;
4490 goto unlock;
4491 }
4492
Johan Hedbergf2252572015-11-18 12:49:20 +02004493 /* We need to flip the bit already here so that
4494 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004495 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004496 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004497
4498 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004499
Johan Hedberg432df052014-08-01 11:13:31 +03004500 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004501 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004502
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004503 /* Since only the advertising data flags will change, there
4504 * is no need to update the scan response data.
4505 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004506 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004507
Johan Hedberg0663ca22013-10-02 13:43:14 +03004508 err = hci_req_run(&req, set_bredr_complete);
4509 if (err < 0)
4510 mgmt_pending_remove(cmd);
4511
4512unlock:
4513 hci_dev_unlock(hdev);
4514 return err;
4515}
4516
Johan Hedberga1443f52015-01-23 15:42:46 +02004517static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4518{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004519 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004520 struct mgmt_mode *cp;
4521
4522 BT_DBG("%s status %u", hdev->name, status);
4523
4524 hci_dev_lock(hdev);
4525
Johan Hedberg333ae952015-03-17 13:48:47 +02004526 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004527 if (!cmd)
4528 goto unlock;
4529
4530 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004531 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4532 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004533 goto remove;
4534 }
4535
4536 cp = cmd->param;
4537
4538 switch (cp->val) {
4539 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004540 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4541 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004542 break;
4543 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004544 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004545 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004546 break;
4547 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004548 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4549 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004550 break;
4551 }
4552
4553 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4554 new_settings(hdev, cmd->sk);
4555
4556remove:
4557 mgmt_pending_remove(cmd);
4558unlock:
4559 hci_dev_unlock(hdev);
4560}
4561
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004562static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4563 void *data, u16 len)
4564{
4565 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004566 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004567 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004568 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004569 int err;
4570
4571 BT_DBG("request for %s", hdev->name);
4572
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004573 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004574 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004575 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4576 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004577
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004578 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004579 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004580 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004581 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4582 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004583
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004584 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004585 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004586 MGMT_STATUS_INVALID_PARAMS);
4587
4588 hci_dev_lock(hdev);
4589
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004590 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004591 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004592 bool changed;
4593
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004594 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004595 changed = !hci_dev_test_and_set_flag(hdev,
4596 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004597 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004598 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004599 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004600 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004601 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004602 changed = hci_dev_test_and_clear_flag(hdev,
4603 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004604 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004605 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004606
4607 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4608 if (err < 0)
4609 goto failed;
4610
4611 if (changed)
4612 err = new_settings(hdev, sk);
4613
4614 goto failed;
4615 }
4616
Johan Hedberg333ae952015-03-17 13:48:47 +02004617 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004618 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4619 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004620 goto failed;
4621 }
4622
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004623 val = !!cp->val;
4624
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004625 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4626 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004627 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4628 goto failed;
4629 }
4630
4631 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4632 if (!cmd) {
4633 err = -ENOMEM;
4634 goto failed;
4635 }
4636
Johan Hedberga1443f52015-01-23 15:42:46 +02004637 hci_req_init(&req, hdev);
4638 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4639 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004640 if (err < 0) {
4641 mgmt_pending_remove(cmd);
4642 goto failed;
4643 }
4644
4645failed:
4646 hci_dev_unlock(hdev);
4647 return err;
4648}
4649
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004650static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4651 void *data, u16 len)
4652{
4653 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004654 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004655 int err;
4656
4657 BT_DBG("request for %s", hdev->name);
4658
Johan Hedbergb97109792014-06-24 14:00:28 +03004659 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004660 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4661 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004662
4663 hci_dev_lock(hdev);
4664
4665 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004666 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004667 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004668 changed = hci_dev_test_and_clear_flag(hdev,
4669 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004670
Johan Hedbergb97109792014-06-24 14:00:28 +03004671 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004672 use_changed = !hci_dev_test_and_set_flag(hdev,
4673 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004674 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004675 use_changed = hci_dev_test_and_clear_flag(hdev,
4676 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004677
4678 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004679 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004680 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4681 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4682 sizeof(mode), &mode);
4683 }
4684
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004685 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4686 if (err < 0)
4687 goto unlock;
4688
4689 if (changed)
4690 err = new_settings(hdev, sk);
4691
4692unlock:
4693 hci_dev_unlock(hdev);
4694 return err;
4695}
4696
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004697static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4698 u16 len)
4699{
4700 struct mgmt_cp_set_privacy *cp = cp_data;
4701 bool changed;
4702 int err;
4703
4704 BT_DBG("request for %s", hdev->name);
4705
4706 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4708 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004709
4710 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004711 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4712 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004713
4714 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004715 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4716 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004717
4718 hci_dev_lock(hdev);
4719
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004720 /* If user space supports this command it is also expected to
4721 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4722 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004723 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004724
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004725 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004726 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004727 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004728 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004729 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004730 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004731 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004732 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004733 }
4734
4735 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4736 if (err < 0)
4737 goto unlock;
4738
4739 if (changed)
4740 err = new_settings(hdev, sk);
4741
4742unlock:
4743 hci_dev_unlock(hdev);
4744 return err;
4745}
4746
Johan Hedberg41edf162014-02-18 10:19:35 +02004747static bool irk_is_valid(struct mgmt_irk_info *irk)
4748{
4749 switch (irk->addr.type) {
4750 case BDADDR_LE_PUBLIC:
4751 return true;
4752
4753 case BDADDR_LE_RANDOM:
4754 /* Two most significant bits shall be set */
4755 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4756 return false;
4757 return true;
4758 }
4759
4760 return false;
4761}
4762
4763static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4764 u16 len)
4765{
4766 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004767 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4768 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004769 u16 irk_count, expected_len;
4770 int i, err;
4771
4772 BT_DBG("request for %s", hdev->name);
4773
4774 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004775 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4776 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004777
4778 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004779 if (irk_count > max_irk_count) {
4780 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004781 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4782 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004783 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004784
4785 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4786 if (expected_len != len) {
4787 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004788 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004789 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4790 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004791 }
4792
4793 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4794
4795 for (i = 0; i < irk_count; i++) {
4796 struct mgmt_irk_info *key = &cp->irks[i];
4797
4798 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004799 return mgmt_cmd_status(sk, hdev->id,
4800 MGMT_OP_LOAD_IRKS,
4801 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004802 }
4803
4804 hci_dev_lock(hdev);
4805
4806 hci_smp_irks_clear(hdev);
4807
4808 for (i = 0; i < irk_count; i++) {
4809 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004810
Johan Hedberg85813a72015-10-21 18:02:59 +03004811 hci_add_irk(hdev, &irk->addr.bdaddr,
4812 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004813 BDADDR_ANY);
4814 }
4815
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004816 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004817
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004818 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004819
4820 hci_dev_unlock(hdev);
4821
4822 return err;
4823}
4824
Johan Hedberg3f706b72013-01-20 14:27:16 +02004825static bool ltk_is_valid(struct mgmt_ltk_info *key)
4826{
4827 if (key->master != 0x00 && key->master != 0x01)
4828 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004829
4830 switch (key->addr.type) {
4831 case BDADDR_LE_PUBLIC:
4832 return true;
4833
4834 case BDADDR_LE_RANDOM:
4835 /* Two most significant bits shall be set */
4836 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4837 return false;
4838 return true;
4839 }
4840
4841 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004842}
4843
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004844static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004845 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004846{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004847 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004848 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4849 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004850 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004851 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004852
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004853 BT_DBG("request for %s", hdev->name);
4854
4855 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004856 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4857 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004858
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004859 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004860 if (key_count > max_key_count) {
4861 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004862 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4863 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004864 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004865
4866 expected_len = sizeof(*cp) + key_count *
4867 sizeof(struct mgmt_ltk_info);
4868 if (expected_len != len) {
4869 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004870 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004871 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4872 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004873 }
4874
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004875 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004876
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004877 for (i = 0; i < key_count; i++) {
4878 struct mgmt_ltk_info *key = &cp->keys[i];
4879
Johan Hedberg3f706b72013-01-20 14:27:16 +02004880 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004881 return mgmt_cmd_status(sk, hdev->id,
4882 MGMT_OP_LOAD_LONG_TERM_KEYS,
4883 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004884 }
4885
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004886 hci_dev_lock(hdev);
4887
4888 hci_smp_ltks_clear(hdev);
4889
4890 for (i = 0; i < key_count; i++) {
4891 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004892 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004893
Johan Hedberg61b43352014-05-29 19:36:53 +03004894 switch (key->type) {
4895 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004896 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004897 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004898 break;
4899 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004900 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004901 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004902 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004903 case MGMT_LTK_P256_UNAUTH:
4904 authenticated = 0x00;
4905 type = SMP_LTK_P256;
4906 break;
4907 case MGMT_LTK_P256_AUTH:
4908 authenticated = 0x01;
4909 type = SMP_LTK_P256;
4910 break;
4911 case MGMT_LTK_P256_DEBUG:
4912 authenticated = 0x00;
4913 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004914 default:
4915 continue;
4916 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004917
Johan Hedberg85813a72015-10-21 18:02:59 +03004918 hci_add_ltk(hdev, &key->addr.bdaddr,
4919 le_addr_type(key->addr.type), type, authenticated,
4920 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004921 }
4922
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004923 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004924 NULL, 0);
4925
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004926 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004927
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004928 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004929}
4930
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004931static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004932{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004933 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004934 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004935 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004936
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004937 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004938
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004939 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004940 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004941 rp.tx_power = conn->tx_power;
4942 rp.max_tx_power = conn->max_tx_power;
4943 } else {
4944 rp.rssi = HCI_RSSI_INVALID;
4945 rp.tx_power = HCI_TX_POWER_INVALID;
4946 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004947 }
4948
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004949 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4950 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004951
4952 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004953 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004954
4955 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004956}
4957
Marcel Holtmann1904a852015-01-11 13:50:44 -08004958static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4959 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004960{
4961 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004962 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004963 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004964 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004965 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004966
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004967 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004968
4969 hci_dev_lock(hdev);
4970
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004971 /* Commands sent in request are either Read RSSI or Read Transmit Power
4972 * Level so we check which one was last sent to retrieve connection
4973 * handle. Both commands have handle as first parameter so it's safe to
4974 * cast data on the same command struct.
4975 *
4976 * First command sent is always Read RSSI and we fail only if it fails.
4977 * In other case we simply override error to indicate success as we
4978 * already remembered if TX power value is actually valid.
4979 */
4980 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4981 if (!cp) {
4982 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004983 status = MGMT_STATUS_SUCCESS;
4984 } else {
4985 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004986 }
4987
4988 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004989 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004990 goto unlock;
4991 }
4992
4993 handle = __le16_to_cpu(cp->handle);
4994 conn = hci_conn_hash_lookup_handle(hdev, handle);
4995 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004996 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004997 goto unlock;
4998 }
4999
Johan Hedberg333ae952015-03-17 13:48:47 +02005000 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005001 if (!cmd)
5002 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005003
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005004 cmd->cmd_complete(cmd, status);
5005 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005006
5007unlock:
5008 hci_dev_unlock(hdev);
5009}
5010
5011static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5012 u16 len)
5013{
5014 struct mgmt_cp_get_conn_info *cp = data;
5015 struct mgmt_rp_get_conn_info rp;
5016 struct hci_conn *conn;
5017 unsigned long conn_info_age;
5018 int err = 0;
5019
5020 BT_DBG("%s", hdev->name);
5021
5022 memset(&rp, 0, sizeof(rp));
5023 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5024 rp.addr.type = cp->addr.type;
5025
5026 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005027 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5028 MGMT_STATUS_INVALID_PARAMS,
5029 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005030
5031 hci_dev_lock(hdev);
5032
5033 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005034 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5035 MGMT_STATUS_NOT_POWERED, &rp,
5036 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005037 goto unlock;
5038 }
5039
5040 if (cp->addr.type == BDADDR_BREDR)
5041 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5042 &cp->addr.bdaddr);
5043 else
5044 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5045
5046 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005047 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5048 MGMT_STATUS_NOT_CONNECTED, &rp,
5049 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005050 goto unlock;
5051 }
5052
Johan Hedberg333ae952015-03-17 13:48:47 +02005053 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005054 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5055 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005056 goto unlock;
5057 }
5058
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005059 /* To avoid client trying to guess when to poll again for information we
5060 * calculate conn info age as random value between min/max set in hdev.
5061 */
5062 conn_info_age = hdev->conn_info_min_age +
5063 prandom_u32_max(hdev->conn_info_max_age -
5064 hdev->conn_info_min_age);
5065
5066 /* Query controller to refresh cached values if they are too old or were
5067 * never read.
5068 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005069 if (time_after(jiffies, conn->conn_info_timestamp +
5070 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005071 !conn->conn_info_timestamp) {
5072 struct hci_request req;
5073 struct hci_cp_read_tx_power req_txp_cp;
5074 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005075 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005076
5077 hci_req_init(&req, hdev);
5078 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5079 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5080 &req_rssi_cp);
5081
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005082 /* For LE links TX power does not change thus we don't need to
5083 * query for it once value is known.
5084 */
5085 if (!bdaddr_type_is_le(cp->addr.type) ||
5086 conn->tx_power == HCI_TX_POWER_INVALID) {
5087 req_txp_cp.handle = cpu_to_le16(conn->handle);
5088 req_txp_cp.type = 0x00;
5089 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5090 sizeof(req_txp_cp), &req_txp_cp);
5091 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005092
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005093 /* Max TX power needs to be read only once per connection */
5094 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5095 req_txp_cp.handle = cpu_to_le16(conn->handle);
5096 req_txp_cp.type = 0x01;
5097 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5098 sizeof(req_txp_cp), &req_txp_cp);
5099 }
5100
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005101 err = hci_req_run(&req, conn_info_refresh_complete);
5102 if (err < 0)
5103 goto unlock;
5104
5105 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5106 data, len);
5107 if (!cmd) {
5108 err = -ENOMEM;
5109 goto unlock;
5110 }
5111
5112 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005113 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005114 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005115
5116 conn->conn_info_timestamp = jiffies;
5117 } else {
5118 /* Cache is valid, just reply with values cached in hci_conn */
5119 rp.rssi = conn->rssi;
5120 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005121 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005122
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005123 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5124 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005125 }
5126
5127unlock:
5128 hci_dev_unlock(hdev);
5129 return err;
5130}
5131
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005132static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005133{
5134 struct hci_conn *conn = cmd->user_data;
5135 struct mgmt_rp_get_clock_info rp;
5136 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005137 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005138
5139 memset(&rp, 0, sizeof(rp));
5140 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5141
5142 if (status)
5143 goto complete;
5144
5145 hdev = hci_dev_get(cmd->index);
5146 if (hdev) {
5147 rp.local_clock = cpu_to_le32(hdev->clock);
5148 hci_dev_put(hdev);
5149 }
5150
5151 if (conn) {
5152 rp.piconet_clock = cpu_to_le32(conn->clock);
5153 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5154 }
5155
5156complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005157 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5158 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005159
5160 if (conn) {
5161 hci_conn_drop(conn);
5162 hci_conn_put(conn);
5163 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005164
5165 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005166}
5167
Marcel Holtmann1904a852015-01-11 13:50:44 -08005168static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005169{
Johan Hedberg95868422014-06-28 17:54:07 +03005170 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005171 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005172 struct hci_conn *conn;
5173
5174 BT_DBG("%s status %u", hdev->name, status);
5175
5176 hci_dev_lock(hdev);
5177
5178 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5179 if (!hci_cp)
5180 goto unlock;
5181
5182 if (hci_cp->which) {
5183 u16 handle = __le16_to_cpu(hci_cp->handle);
5184 conn = hci_conn_hash_lookup_handle(hdev, handle);
5185 } else {
5186 conn = NULL;
5187 }
5188
Johan Hedberg333ae952015-03-17 13:48:47 +02005189 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005190 if (!cmd)
5191 goto unlock;
5192
Johan Hedberg69487372014-12-05 13:36:07 +02005193 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005194 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005195
5196unlock:
5197 hci_dev_unlock(hdev);
5198}
5199
5200static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5201 u16 len)
5202{
5203 struct mgmt_cp_get_clock_info *cp = data;
5204 struct mgmt_rp_get_clock_info rp;
5205 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005206 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005207 struct hci_request req;
5208 struct hci_conn *conn;
5209 int err;
5210
5211 BT_DBG("%s", hdev->name);
5212
5213 memset(&rp, 0, sizeof(rp));
5214 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5215 rp.addr.type = cp->addr.type;
5216
5217 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005218 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5219 MGMT_STATUS_INVALID_PARAMS,
5220 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005221
5222 hci_dev_lock(hdev);
5223
5224 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005225 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5226 MGMT_STATUS_NOT_POWERED, &rp,
5227 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005228 goto unlock;
5229 }
5230
5231 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5232 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5233 &cp->addr.bdaddr);
5234 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005235 err = mgmt_cmd_complete(sk, hdev->id,
5236 MGMT_OP_GET_CLOCK_INFO,
5237 MGMT_STATUS_NOT_CONNECTED,
5238 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005239 goto unlock;
5240 }
5241 } else {
5242 conn = NULL;
5243 }
5244
5245 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5246 if (!cmd) {
5247 err = -ENOMEM;
5248 goto unlock;
5249 }
5250
Johan Hedberg69487372014-12-05 13:36:07 +02005251 cmd->cmd_complete = clock_info_cmd_complete;
5252
Johan Hedberg95868422014-06-28 17:54:07 +03005253 hci_req_init(&req, hdev);
5254
5255 memset(&hci_cp, 0, sizeof(hci_cp));
5256 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5257
5258 if (conn) {
5259 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005260 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005261
5262 hci_cp.handle = cpu_to_le16(conn->handle);
5263 hci_cp.which = 0x01; /* Piconet clock */
5264 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5265 }
5266
5267 err = hci_req_run(&req, get_clock_info_complete);
5268 if (err < 0)
5269 mgmt_pending_remove(cmd);
5270
5271unlock:
5272 hci_dev_unlock(hdev);
5273 return err;
5274}
5275
Johan Hedberg5a154e62014-12-19 22:26:02 +02005276static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5277{
5278 struct hci_conn *conn;
5279
5280 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5281 if (!conn)
5282 return false;
5283
5284 if (conn->dst_type != type)
5285 return false;
5286
5287 if (conn->state != BT_CONNECTED)
5288 return false;
5289
5290 return true;
5291}
5292
5293/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005294static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005295 u8 addr_type, u8 auto_connect)
5296{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005297 struct hci_conn_params *params;
5298
5299 params = hci_conn_params_add(hdev, addr, addr_type);
5300 if (!params)
5301 return -EIO;
5302
5303 if (params->auto_connect == auto_connect)
5304 return 0;
5305
5306 list_del_init(&params->action);
5307
5308 switch (auto_connect) {
5309 case HCI_AUTO_CONN_DISABLED:
5310 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005311 /* If auto connect is being disabled when we're trying to
5312 * connect to device, keep connecting.
5313 */
5314 if (params->explicit_connect)
5315 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005316 break;
5317 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005318 if (params->explicit_connect)
5319 list_add(&params->action, &hdev->pend_le_conns);
5320 else
5321 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005322 break;
5323 case HCI_AUTO_CONN_DIRECT:
5324 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005325 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005326 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005327 break;
5328 }
5329
5330 params->auto_connect = auto_connect;
5331
5332 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5333 auto_connect);
5334
5335 return 0;
5336}
5337
Marcel Holtmann8afef092014-06-29 22:28:34 +02005338static void device_added(struct sock *sk, struct hci_dev *hdev,
5339 bdaddr_t *bdaddr, u8 type, u8 action)
5340{
5341 struct mgmt_ev_device_added ev;
5342
5343 bacpy(&ev.addr.bdaddr, bdaddr);
5344 ev.addr.type = type;
5345 ev.action = action;
5346
5347 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5348}
5349
Marcel Holtmann2faade52014-06-29 19:44:03 +02005350static int add_device(struct sock *sk, struct hci_dev *hdev,
5351 void *data, u16 len)
5352{
5353 struct mgmt_cp_add_device *cp = data;
5354 u8 auto_conn, addr_type;
5355 int err;
5356
5357 BT_DBG("%s", hdev->name);
5358
Johan Hedberg66593582014-07-09 12:59:14 +03005359 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005360 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005361 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5362 MGMT_STATUS_INVALID_PARAMS,
5363 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005364
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005365 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005366 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5367 MGMT_STATUS_INVALID_PARAMS,
5368 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005369
5370 hci_dev_lock(hdev);
5371
Johan Hedberg66593582014-07-09 12:59:14 +03005372 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005373 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005374 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005375 err = mgmt_cmd_complete(sk, hdev->id,
5376 MGMT_OP_ADD_DEVICE,
5377 MGMT_STATUS_INVALID_PARAMS,
5378 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005379 goto unlock;
5380 }
5381
5382 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5383 cp->addr.type);
5384 if (err)
5385 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005386
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005387 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005388
Johan Hedberg66593582014-07-09 12:59:14 +03005389 goto added;
5390 }
5391
Johan Hedberg85813a72015-10-21 18:02:59 +03005392 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005393
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005394 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005395 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005396 else if (cp->action == 0x01)
5397 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005398 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005399 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005400
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005401 /* Kernel internally uses conn_params with resolvable private
5402 * address, but Add Device allows only identity addresses.
5403 * Make sure it is enforced before calling
5404 * hci_conn_params_lookup.
5405 */
5406 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005407 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5408 MGMT_STATUS_INVALID_PARAMS,
5409 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005410 goto unlock;
5411 }
5412
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005413 /* If the connection parameters don't exist for this device,
5414 * they will be created and configured with defaults.
5415 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005416 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005417 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005418 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5419 MGMT_STATUS_FAILED, &cp->addr,
5420 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005421 goto unlock;
5422 }
5423
Johan Hedberg51d7a942015-11-11 08:11:18 +02005424 hci_update_background_scan(hdev);
5425
Johan Hedberg66593582014-07-09 12:59:14 +03005426added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005427 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5428
Johan Hedberg51d7a942015-11-11 08:11:18 +02005429 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5430 MGMT_STATUS_SUCCESS, &cp->addr,
5431 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005432
5433unlock:
5434 hci_dev_unlock(hdev);
5435 return err;
5436}
5437
Marcel Holtmann8afef092014-06-29 22:28:34 +02005438static void device_removed(struct sock *sk, struct hci_dev *hdev,
5439 bdaddr_t *bdaddr, u8 type)
5440{
5441 struct mgmt_ev_device_removed ev;
5442
5443 bacpy(&ev.addr.bdaddr, bdaddr);
5444 ev.addr.type = type;
5445
5446 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5447}
5448
Marcel Holtmann2faade52014-06-29 19:44:03 +02005449static int remove_device(struct sock *sk, struct hci_dev *hdev,
5450 void *data, u16 len)
5451{
5452 struct mgmt_cp_remove_device *cp = data;
5453 int err;
5454
5455 BT_DBG("%s", hdev->name);
5456
5457 hci_dev_lock(hdev);
5458
5459 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005460 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005461 u8 addr_type;
5462
Johan Hedberg66593582014-07-09 12:59:14 +03005463 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005464 err = mgmt_cmd_complete(sk, hdev->id,
5465 MGMT_OP_REMOVE_DEVICE,
5466 MGMT_STATUS_INVALID_PARAMS,
5467 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005468 goto unlock;
5469 }
5470
Johan Hedberg66593582014-07-09 12:59:14 +03005471 if (cp->addr.type == BDADDR_BREDR) {
5472 err = hci_bdaddr_list_del(&hdev->whitelist,
5473 &cp->addr.bdaddr,
5474 cp->addr.type);
5475 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005476 err = mgmt_cmd_complete(sk, hdev->id,
5477 MGMT_OP_REMOVE_DEVICE,
5478 MGMT_STATUS_INVALID_PARAMS,
5479 &cp->addr,
5480 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005481 goto unlock;
5482 }
5483
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005484 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005485
Johan Hedberg66593582014-07-09 12:59:14 +03005486 device_removed(sk, hdev, &cp->addr.bdaddr,
5487 cp->addr.type);
5488 goto complete;
5489 }
5490
Johan Hedberg85813a72015-10-21 18:02:59 +03005491 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005492
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005493 /* Kernel internally uses conn_params with resolvable private
5494 * address, but Remove Device allows only identity addresses.
5495 * Make sure it is enforced before calling
5496 * hci_conn_params_lookup.
5497 */
5498 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005499 err = mgmt_cmd_complete(sk, hdev->id,
5500 MGMT_OP_REMOVE_DEVICE,
5501 MGMT_STATUS_INVALID_PARAMS,
5502 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005503 goto unlock;
5504 }
5505
Johan Hedbergc71593d2014-07-02 17:37:28 +03005506 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5507 addr_type);
5508 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005509 err = mgmt_cmd_complete(sk, hdev->id,
5510 MGMT_OP_REMOVE_DEVICE,
5511 MGMT_STATUS_INVALID_PARAMS,
5512 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005513 goto unlock;
5514 }
5515
Johan Hedberg679d2b62015-10-16 10:07:52 +03005516 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5517 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005518 err = mgmt_cmd_complete(sk, hdev->id,
5519 MGMT_OP_REMOVE_DEVICE,
5520 MGMT_STATUS_INVALID_PARAMS,
5521 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005522 goto unlock;
5523 }
5524
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005525 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005526 list_del(&params->list);
5527 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005528 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005529
5530 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005531 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005532 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005533 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005534
Marcel Holtmann2faade52014-06-29 19:44:03 +02005535 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005536 err = mgmt_cmd_complete(sk, hdev->id,
5537 MGMT_OP_REMOVE_DEVICE,
5538 MGMT_STATUS_INVALID_PARAMS,
5539 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005540 goto unlock;
5541 }
5542
Johan Hedberg66593582014-07-09 12:59:14 +03005543 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5544 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5545 list_del(&b->list);
5546 kfree(b);
5547 }
5548
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005549 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005550
Johan Hedberg19de0822014-07-06 13:06:51 +03005551 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5552 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5553 continue;
5554 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005555 if (p->explicit_connect) {
5556 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5557 continue;
5558 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005559 list_del(&p->action);
5560 list_del(&p->list);
5561 kfree(p);
5562 }
5563
5564 BT_DBG("All LE connection parameters were removed");
5565
Johan Hedberg51d7a942015-11-11 08:11:18 +02005566 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005567 }
5568
Johan Hedberg66593582014-07-09 12:59:14 +03005569complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005570 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5571 MGMT_STATUS_SUCCESS, &cp->addr,
5572 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005573unlock:
5574 hci_dev_unlock(hdev);
5575 return err;
5576}
5577
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005578static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5579 u16 len)
5580{
5581 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005582 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5583 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005584 u16 param_count, expected_len;
5585 int i;
5586
5587 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005588 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5589 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005590
5591 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005592 if (param_count > max_param_count) {
5593 BT_ERR("load_conn_param: too big param_count value %u",
5594 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005595 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5596 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005597 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005598
5599 expected_len = sizeof(*cp) + param_count *
5600 sizeof(struct mgmt_conn_param);
5601 if (expected_len != len) {
5602 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5603 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005604 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5605 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005606 }
5607
5608 BT_DBG("%s param_count %u", hdev->name, param_count);
5609
5610 hci_dev_lock(hdev);
5611
5612 hci_conn_params_clear_disabled(hdev);
5613
5614 for (i = 0; i < param_count; i++) {
5615 struct mgmt_conn_param *param = &cp->params[i];
5616 struct hci_conn_params *hci_param;
5617 u16 min, max, latency, timeout;
5618 u8 addr_type;
5619
5620 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5621 param->addr.type);
5622
5623 if (param->addr.type == BDADDR_LE_PUBLIC) {
5624 addr_type = ADDR_LE_DEV_PUBLIC;
5625 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5626 addr_type = ADDR_LE_DEV_RANDOM;
5627 } else {
5628 BT_ERR("Ignoring invalid connection parameters");
5629 continue;
5630 }
5631
5632 min = le16_to_cpu(param->min_interval);
5633 max = le16_to_cpu(param->max_interval);
5634 latency = le16_to_cpu(param->latency);
5635 timeout = le16_to_cpu(param->timeout);
5636
5637 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5638 min, max, latency, timeout);
5639
5640 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5641 BT_ERR("Ignoring invalid connection parameters");
5642 continue;
5643 }
5644
5645 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5646 addr_type);
5647 if (!hci_param) {
5648 BT_ERR("Failed to add connection parameters");
5649 continue;
5650 }
5651
5652 hci_param->conn_min_interval = min;
5653 hci_param->conn_max_interval = max;
5654 hci_param->conn_latency = latency;
5655 hci_param->supervision_timeout = timeout;
5656 }
5657
5658 hci_dev_unlock(hdev);
5659
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005660 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5661 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005662}
5663
Marcel Holtmanndbece372014-07-04 18:11:55 +02005664static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5665 void *data, u16 len)
5666{
5667 struct mgmt_cp_set_external_config *cp = data;
5668 bool changed;
5669 int err;
5670
5671 BT_DBG("%s", hdev->name);
5672
5673 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5675 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005676
5677 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005678 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5679 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005680
5681 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005682 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5683 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005684
5685 hci_dev_lock(hdev);
5686
5687 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005688 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005689 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005690 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005691
5692 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5693 if (err < 0)
5694 goto unlock;
5695
5696 if (!changed)
5697 goto unlock;
5698
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005699 err = new_options(hdev, sk);
5700
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005701 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005702 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005703
Marcel Holtmann516018a2015-03-13 02:11:04 -07005704 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005705 hci_dev_set_flag(hdev, HCI_CONFIG);
5706 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005707
5708 queue_work(hdev->req_workqueue, &hdev->power_on);
5709 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005710 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005711 mgmt_index_added(hdev);
5712 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005713 }
5714
5715unlock:
5716 hci_dev_unlock(hdev);
5717 return err;
5718}
5719
Marcel Holtmann9713c172014-07-06 12:11:15 +02005720static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5721 void *data, u16 len)
5722{
5723 struct mgmt_cp_set_public_address *cp = data;
5724 bool changed;
5725 int err;
5726
5727 BT_DBG("%s", hdev->name);
5728
5729 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005730 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5731 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005732
5733 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005734 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5735 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005736
5737 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005738 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5739 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005740
5741 hci_dev_lock(hdev);
5742
5743 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5744 bacpy(&hdev->public_addr, &cp->bdaddr);
5745
5746 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5747 if (err < 0)
5748 goto unlock;
5749
5750 if (!changed)
5751 goto unlock;
5752
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005753 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005754 err = new_options(hdev, sk);
5755
5756 if (is_configured(hdev)) {
5757 mgmt_index_removed(hdev);
5758
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005759 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005760
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005761 hci_dev_set_flag(hdev, HCI_CONFIG);
5762 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005763
5764 queue_work(hdev->req_workqueue, &hdev->power_on);
5765 }
5766
5767unlock:
5768 hci_dev_unlock(hdev);
5769 return err;
5770}
5771
Marcel Holtmannbea41602015-03-14 22:43:17 -07005772static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5773 u8 data_len)
5774{
5775 eir[eir_len++] = sizeof(type) + data_len;
5776 eir[eir_len++] = type;
5777 memcpy(&eir[eir_len], data, data_len);
5778 eir_len += data_len;
5779
5780 return eir_len;
5781}
5782
Johan Hedberg40f66c02015-04-07 21:52:22 +03005783static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5784 u16 opcode, struct sk_buff *skb)
5785{
5786 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5787 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5788 u8 *h192, *r192, *h256, *r256;
5789 struct mgmt_pending_cmd *cmd;
5790 u16 eir_len;
5791 int err;
5792
5793 BT_DBG("%s status %u", hdev->name, status);
5794
5795 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5796 if (!cmd)
5797 return;
5798
5799 mgmt_cp = cmd->param;
5800
5801 if (status) {
5802 status = mgmt_status(status);
5803 eir_len = 0;
5804
5805 h192 = NULL;
5806 r192 = NULL;
5807 h256 = NULL;
5808 r256 = NULL;
5809 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5810 struct hci_rp_read_local_oob_data *rp;
5811
5812 if (skb->len != sizeof(*rp)) {
5813 status = MGMT_STATUS_FAILED;
5814 eir_len = 0;
5815 } else {
5816 status = MGMT_STATUS_SUCCESS;
5817 rp = (void *)skb->data;
5818
5819 eir_len = 5 + 18 + 18;
5820 h192 = rp->hash;
5821 r192 = rp->rand;
5822 h256 = NULL;
5823 r256 = NULL;
5824 }
5825 } else {
5826 struct hci_rp_read_local_oob_ext_data *rp;
5827
5828 if (skb->len != sizeof(*rp)) {
5829 status = MGMT_STATUS_FAILED;
5830 eir_len = 0;
5831 } else {
5832 status = MGMT_STATUS_SUCCESS;
5833 rp = (void *)skb->data;
5834
5835 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5836 eir_len = 5 + 18 + 18;
5837 h192 = NULL;
5838 r192 = NULL;
5839 } else {
5840 eir_len = 5 + 18 + 18 + 18 + 18;
5841 h192 = rp->hash192;
5842 r192 = rp->rand192;
5843 }
5844
5845 h256 = rp->hash256;
5846 r256 = rp->rand256;
5847 }
5848 }
5849
5850 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5851 if (!mgmt_rp)
5852 goto done;
5853
5854 if (status)
5855 goto send_rsp;
5856
5857 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5858 hdev->dev_class, 3);
5859
5860 if (h192 && r192) {
5861 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5862 EIR_SSP_HASH_C192, h192, 16);
5863 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5864 EIR_SSP_RAND_R192, r192, 16);
5865 }
5866
5867 if (h256 && r256) {
5868 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5869 EIR_SSP_HASH_C256, h256, 16);
5870 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5871 EIR_SSP_RAND_R256, r256, 16);
5872 }
5873
5874send_rsp:
5875 mgmt_rp->type = mgmt_cp->type;
5876 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5877
5878 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5879 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5880 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5881 if (err < 0 || status)
5882 goto done;
5883
5884 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5885
5886 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5887 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5888 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5889done:
5890 kfree(mgmt_rp);
5891 mgmt_pending_remove(cmd);
5892}
5893
5894static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5895 struct mgmt_cp_read_local_oob_ext_data *cp)
5896{
5897 struct mgmt_pending_cmd *cmd;
5898 struct hci_request req;
5899 int err;
5900
5901 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5902 cp, sizeof(*cp));
5903 if (!cmd)
5904 return -ENOMEM;
5905
5906 hci_req_init(&req, hdev);
5907
5908 if (bredr_sc_enabled(hdev))
5909 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5910 else
5911 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5912
5913 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5914 if (err < 0) {
5915 mgmt_pending_remove(cmd);
5916 return err;
5917 }
5918
5919 return 0;
5920}
5921
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005922static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5923 void *data, u16 data_len)
5924{
5925 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5926 struct mgmt_rp_read_local_oob_ext_data *rp;
5927 size_t rp_len;
5928 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005929 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005930 int err;
5931
5932 BT_DBG("%s", hdev->name);
5933
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005934 if (hdev_is_powered(hdev)) {
5935 switch (cp->type) {
5936 case BIT(BDADDR_BREDR):
5937 status = mgmt_bredr_support(hdev);
5938 if (status)
5939 eir_len = 0;
5940 else
5941 eir_len = 5;
5942 break;
5943 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5944 status = mgmt_le_support(hdev);
5945 if (status)
5946 eir_len = 0;
5947 else
5948 eir_len = 9 + 3 + 18 + 18 + 3;
5949 break;
5950 default:
5951 status = MGMT_STATUS_INVALID_PARAMS;
5952 eir_len = 0;
5953 break;
5954 }
5955 } else {
5956 status = MGMT_STATUS_NOT_POWERED;
5957 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005958 }
5959
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005960 rp_len = sizeof(*rp) + eir_len;
5961 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005962 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005963 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005964
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005965 if (status)
5966 goto complete;
5967
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005968 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005969
5970 eir_len = 0;
5971 switch (cp->type) {
5972 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005973 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5974 err = read_local_ssp_oob_req(hdev, sk, cp);
5975 hci_dev_unlock(hdev);
5976 if (!err)
5977 goto done;
5978
5979 status = MGMT_STATUS_FAILED;
5980 goto complete;
5981 } else {
5982 eir_len = eir_append_data(rp->eir, eir_len,
5983 EIR_CLASS_OF_DEV,
5984 hdev->dev_class, 3);
5985 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005986 break;
5987 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005988 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5989 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005990 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005991 status = MGMT_STATUS_FAILED;
5992 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005993 }
5994
Marcel Holtmanne2135682015-04-02 12:00:58 -07005995 /* This should return the active RPA, but since the RPA
5996 * is only programmed on demand, it is really hard to fill
5997 * this in at the moment. For now disallow retrieving
5998 * local out-of-band data when privacy is in use.
5999 *
6000 * Returning the identity address will not help here since
6001 * pairing happens before the identity resolving key is
6002 * known and thus the connection establishment happens
6003 * based on the RPA and not the identity address.
6004 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006005 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006006 hci_dev_unlock(hdev);
6007 status = MGMT_STATUS_REJECTED;
6008 goto complete;
6009 }
6010
6011 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6012 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6013 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6014 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006015 memcpy(addr, &hdev->static_addr, 6);
6016 addr[6] = 0x01;
6017 } else {
6018 memcpy(addr, &hdev->bdaddr, 6);
6019 addr[6] = 0x00;
6020 }
6021
6022 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6023 addr, sizeof(addr));
6024
6025 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6026 role = 0x02;
6027 else
6028 role = 0x01;
6029
6030 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6031 &role, sizeof(role));
6032
Marcel Holtmann5082a592015-03-16 12:39:00 -07006033 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6034 eir_len = eir_append_data(rp->eir, eir_len,
6035 EIR_LE_SC_CONFIRM,
6036 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006037
Marcel Holtmann5082a592015-03-16 12:39:00 -07006038 eir_len = eir_append_data(rp->eir, eir_len,
6039 EIR_LE_SC_RANDOM,
6040 rand, sizeof(rand));
6041 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006042
Johan Hedbergf2252572015-11-18 12:49:20 +02006043 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006044
6045 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6046 flags |= LE_AD_NO_BREDR;
6047
6048 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6049 &flags, sizeof(flags));
6050 break;
6051 }
6052
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006053 hci_dev_unlock(hdev);
6054
Marcel Holtmann72000df2015-03-16 16:11:21 -07006055 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6056
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006057 status = MGMT_STATUS_SUCCESS;
6058
6059complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006060 rp->type = cp->type;
6061 rp->eir_len = cpu_to_le16(eir_len);
6062
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006063 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006064 status, rp, sizeof(*rp) + eir_len);
6065 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006066 goto done;
6067
6068 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6069 rp, sizeof(*rp) + eir_len,
6070 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006071
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006072done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006073 kfree(rp);
6074
6075 return err;
6076}
6077
Arman Uguray089fa8c2015-03-25 18:53:45 -07006078static u32 get_supported_adv_flags(struct hci_dev *hdev)
6079{
6080 u32 flags = 0;
6081
6082 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6083 flags |= MGMT_ADV_FLAG_DISCOV;
6084 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6085 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
6086
6087 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
6088 flags |= MGMT_ADV_FLAG_TX_POWER;
6089
6090 return flags;
6091}
6092
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006093static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6094 void *data, u16 data_len)
6095{
6096 struct mgmt_rp_read_adv_features *rp;
6097 size_t rp_len;
Florian Grandel286e0c82015-06-18 03:16:38 +02006098 int err, i;
Arman Uguray24b4f382015-03-23 15:57:12 -07006099 bool instance;
Florian Grandel286e0c82015-06-18 03:16:38 +02006100 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006101 u32 supported_flags;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006102
6103 BT_DBG("%s", hdev->name);
6104
Arman Uguray089fa8c2015-03-25 18:53:45 -07006105 if (!lmp_le_capable(hdev))
6106 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6107 MGMT_STATUS_REJECTED);
6108
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006109 hci_dev_lock(hdev);
6110
6111 rp_len = sizeof(*rp);
Arman Uguray24b4f382015-03-23 15:57:12 -07006112
Arman Uguray24b4f382015-03-23 15:57:12 -07006113 instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
6114 if (instance)
Florian Grandel286e0c82015-06-18 03:16:38 +02006115 rp_len += hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006116
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006117 rp = kmalloc(rp_len, GFP_ATOMIC);
6118 if (!rp) {
6119 hci_dev_unlock(hdev);
6120 return -ENOMEM;
6121 }
6122
Arman Uguray089fa8c2015-03-25 18:53:45 -07006123 supported_flags = get_supported_adv_flags(hdev);
6124
6125 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006126 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6127 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006128 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Arman Uguray24b4f382015-03-23 15:57:12 -07006129
Arman Uguray24b4f382015-03-23 15:57:12 -07006130 if (instance) {
Florian Grandel286e0c82015-06-18 03:16:38 +02006131 i = 0;
6132 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6133 if (i >= hdev->adv_instance_cnt)
6134 break;
6135
6136 rp->instance[i] = adv_instance->instance;
6137 i++;
6138 }
6139 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006140 } else {
6141 rp->num_instances = 0;
6142 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006143
6144 hci_dev_unlock(hdev);
6145
6146 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6147 MGMT_STATUS_SUCCESS, rp, rp_len);
6148
6149 kfree(rp);
6150
6151 return err;
6152}
6153
Arman Uguray4117ed72015-03-23 15:57:14 -07006154static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006155 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006156{
Arman Uguray4117ed72015-03-23 15:57:14 -07006157 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006158 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07006159 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07006160 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07006161
Marcel Holtmann31a32482015-11-19 16:16:42 +01006162 if (is_adv_data) {
6163 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6164 MGMT_ADV_FLAG_LIMITED_DISCOV |
6165 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
6166 flags_managed = true;
6167 max_len -= 3;
6168 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006169
Marcel Holtmann31a32482015-11-19 16:16:42 +01006170 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
6171 tx_power_managed = true;
6172 max_len -= 3;
6173 }
Arman Uguray5507e352015-03-25 18:53:44 -07006174 }
6175
Arman Uguray4117ed72015-03-23 15:57:14 -07006176 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006177 return false;
6178
Arman Uguray4117ed72015-03-23 15:57:14 -07006179 /* Make sure that the data is correctly formatted. */
6180 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6181 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006182
Arman Ugurayb44133f2015-03-25 18:53:41 -07006183 if (flags_managed && data[i + 1] == EIR_FLAGS)
6184 return false;
6185
Arman Uguray5507e352015-03-25 18:53:44 -07006186 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
6187 return false;
6188
Arman Uguray24b4f382015-03-23 15:57:12 -07006189 /* If the current field length would exceed the total data
6190 * length, then it's invalid.
6191 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006192 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006193 return false;
6194 }
6195
6196 return true;
6197}
6198
Arman Uguray24b4f382015-03-23 15:57:12 -07006199static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6200 u16 opcode)
6201{
6202 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006203 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006204 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006205 struct adv_info *adv_instance, *n;
6206 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006207
6208 BT_DBG("status %d", status);
6209
6210 hci_dev_lock(hdev);
6211
6212 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6213
Florian Grandelfffd38b2015-06-18 03:16:47 +02006214 if (status)
Arman Uguray24b4f382015-03-23 15:57:12 -07006215 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006216
6217 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6218 if (!adv_instance->pending)
6219 continue;
6220
6221 if (!status) {
6222 adv_instance->pending = false;
6223 continue;
6224 }
6225
6226 instance = adv_instance->instance;
6227
6228 if (hdev->cur_adv_instance == instance)
6229 cancel_adv_timeout(hdev);
6230
6231 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006232 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006233 }
6234
6235 if (!cmd)
6236 goto unlock;
6237
Florian Grandelfffd38b2015-06-18 03:16:47 +02006238 cp = cmd->param;
6239 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006240
6241 if (status)
6242 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6243 mgmt_status(status));
6244 else
6245 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6246 mgmt_status(status), &rp, sizeof(rp));
6247
6248 mgmt_pending_remove(cmd);
6249
6250unlock:
6251 hci_dev_unlock(hdev);
6252}
6253
6254static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6255 void *data, u16 data_len)
6256{
6257 struct mgmt_cp_add_advertising *cp = data;
6258 struct mgmt_rp_add_advertising rp;
6259 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006260 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006261 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006262 u16 timeout, duration;
6263 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6264 u8 schedule_instance = 0;
6265 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006266 int err;
6267 struct mgmt_pending_cmd *cmd;
6268 struct hci_request req;
6269
6270 BT_DBG("%s", hdev->name);
6271
6272 status = mgmt_le_support(hdev);
6273 if (status)
6274 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6275 status);
6276
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006277 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6278 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6279 MGMT_STATUS_INVALID_PARAMS);
6280
Arman Uguray24b4f382015-03-23 15:57:12 -07006281 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006282 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006283 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006284
Florian Grandelfffd38b2015-06-18 03:16:47 +02006285 /* The current implementation only supports a subset of the specified
6286 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006287 */
6288 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006289 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006290 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6291 MGMT_STATUS_INVALID_PARAMS);
6292
6293 hci_dev_lock(hdev);
6294
Arman Uguray912098a2015-03-23 15:57:15 -07006295 if (timeout && !hdev_is_powered(hdev)) {
6296 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6297 MGMT_STATUS_REJECTED);
6298 goto unlock;
6299 }
6300
Arman Uguray24b4f382015-03-23 15:57:12 -07006301 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006302 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006303 pending_find(MGMT_OP_SET_LE, hdev)) {
6304 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6305 MGMT_STATUS_BUSY);
6306 goto unlock;
6307 }
6308
Arman Ugurayb44133f2015-03-25 18:53:41 -07006309 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006310 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006311 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006312 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6313 MGMT_STATUS_INVALID_PARAMS);
6314 goto unlock;
6315 }
6316
Florian Grandelfffd38b2015-06-18 03:16:47 +02006317 err = hci_add_adv_instance(hdev, cp->instance, flags,
6318 cp->adv_data_len, cp->data,
6319 cp->scan_rsp_len,
6320 cp->data + cp->adv_data_len,
6321 timeout, duration);
6322 if (err < 0) {
6323 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6324 MGMT_STATUS_FAILED);
6325 goto unlock;
6326 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006327
Florian Grandelfffd38b2015-06-18 03:16:47 +02006328 /* Only trigger an advertising added event if a new instance was
6329 * actually added.
6330 */
6331 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006332 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006333
Florian Grandelfffd38b2015-06-18 03:16:47 +02006334 hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
Arman Uguray24b4f382015-03-23 15:57:12 -07006335
Florian Grandelfffd38b2015-06-18 03:16:47 +02006336 if (hdev->cur_adv_instance == cp->instance) {
6337 /* If the currently advertised instance is being changed then
6338 * cancel the current advertising and schedule the next
6339 * instance. If there is only one instance then the overridden
6340 * advertising data will be visible right away.
6341 */
6342 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006343
Florian Grandelfffd38b2015-06-18 03:16:47 +02006344 next_instance = hci_get_next_instance(hdev, cp->instance);
6345 if (next_instance)
6346 schedule_instance = next_instance->instance;
6347 } else if (!hdev->adv_instance_timeout) {
6348 /* Immediately advertise the new instance if no other
6349 * instance is currently being advertised.
6350 */
6351 schedule_instance = cp->instance;
6352 }
Arman Uguray912098a2015-03-23 15:57:15 -07006353
Florian Grandelfffd38b2015-06-18 03:16:47 +02006354 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6355 * there is no instance to be advertised then we have no HCI
6356 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006357 */
6358 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006359 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6360 !schedule_instance) {
6361 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006362 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6363 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6364 goto unlock;
6365 }
6366
6367 /* We're good to go, update advertising data, parameters, and start
6368 * advertising.
6369 */
6370 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6371 data_len);
6372 if (!cmd) {
6373 err = -ENOMEM;
6374 goto unlock;
6375 }
6376
6377 hci_req_init(&req, hdev);
6378
Johan Hedbergf2252572015-11-18 12:49:20 +02006379 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006380
Florian Grandelfffd38b2015-06-18 03:16:47 +02006381 if (!err)
6382 err = hci_req_run(&req, add_advertising_complete);
6383
Arman Uguray24b4f382015-03-23 15:57:12 -07006384 if (err < 0)
6385 mgmt_pending_remove(cmd);
6386
6387unlock:
6388 hci_dev_unlock(hdev);
6389
6390 return err;
6391}
6392
Arman Ugurayda9293352015-03-23 15:57:13 -07006393static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6394 u16 opcode)
6395{
6396 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006397 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006398 struct mgmt_rp_remove_advertising rp;
6399
6400 BT_DBG("status %d", status);
6401
6402 hci_dev_lock(hdev);
6403
6404 /* A failure status here only means that we failed to disable
6405 * advertising. Otherwise, the advertising instance has been removed,
6406 * so report success.
6407 */
6408 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6409 if (!cmd)
6410 goto unlock;
6411
Florian Grandel01948332015-06-18 03:16:48 +02006412 cp = cmd->param;
6413 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006414
6415 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6416 &rp, sizeof(rp));
6417 mgmt_pending_remove(cmd);
6418
6419unlock:
6420 hci_dev_unlock(hdev);
6421}
6422
6423static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6424 void *data, u16 data_len)
6425{
6426 struct mgmt_cp_remove_advertising *cp = data;
6427 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006428 struct mgmt_pending_cmd *cmd;
6429 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006430 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006431
6432 BT_DBG("%s", hdev->name);
6433
Arman Ugurayda9293352015-03-23 15:57:13 -07006434 hci_dev_lock(hdev);
6435
Johan Hedberg952497b2015-06-18 21:05:31 +03006436 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006437 err = mgmt_cmd_status(sk, hdev->id,
6438 MGMT_OP_REMOVE_ADVERTISING,
6439 MGMT_STATUS_INVALID_PARAMS);
6440 goto unlock;
6441 }
6442
Arman Ugurayda9293352015-03-23 15:57:13 -07006443 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6444 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6445 pending_find(MGMT_OP_SET_LE, hdev)) {
6446 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6447 MGMT_STATUS_BUSY);
6448 goto unlock;
6449 }
6450
6451 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
6452 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6453 MGMT_STATUS_INVALID_PARAMS);
6454 goto unlock;
6455 }
6456
Florian Grandel01948332015-06-18 03:16:48 +02006457 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006458
Johan Hedbergf2252572015-11-18 12:49:20 +02006459 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006460
Florian Grandel01948332015-06-18 03:16:48 +02006461 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006462 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006463
Florian Grandel01948332015-06-18 03:16:48 +02006464 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6465 * flag is set or the device isn't powered then we have no HCI
6466 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006467 */
Florian Grandel01948332015-06-18 03:16:48 +02006468 if (skb_queue_empty(&req.cmd_q) ||
6469 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006470 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006471 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006472 err = mgmt_cmd_complete(sk, hdev->id,
6473 MGMT_OP_REMOVE_ADVERTISING,
6474 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6475 goto unlock;
6476 }
6477
6478 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6479 data_len);
6480 if (!cmd) {
6481 err = -ENOMEM;
6482 goto unlock;
6483 }
6484
Arman Ugurayda9293352015-03-23 15:57:13 -07006485 err = hci_req_run(&req, remove_advertising_complete);
6486 if (err < 0)
6487 mgmt_pending_remove(cmd);
6488
6489unlock:
6490 hci_dev_unlock(hdev);
6491
6492 return err;
6493}
6494
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006495static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6496{
6497 u8 max_len = HCI_MAX_AD_LENGTH;
6498
6499 if (is_adv_data) {
6500 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6501 MGMT_ADV_FLAG_LIMITED_DISCOV |
6502 MGMT_ADV_FLAG_MANAGED_FLAGS))
6503 max_len -= 3;
6504
6505 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6506 max_len -= 3;
6507 }
6508
6509 return max_len;
6510}
6511
6512static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6513 void *data, u16 data_len)
6514{
6515 struct mgmt_cp_get_adv_size_info *cp = data;
6516 struct mgmt_rp_get_adv_size_info rp;
6517 u32 flags, supported_flags;
6518 int err;
6519
6520 BT_DBG("%s", hdev->name);
6521
6522 if (!lmp_le_capable(hdev))
6523 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6524 MGMT_STATUS_REJECTED);
6525
6526 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6527 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6528 MGMT_STATUS_INVALID_PARAMS);
6529
6530 flags = __le32_to_cpu(cp->flags);
6531
6532 /* The current implementation only supports a subset of the specified
6533 * flags.
6534 */
6535 supported_flags = get_supported_adv_flags(hdev);
6536 if (flags & ~supported_flags)
6537 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6538 MGMT_STATUS_INVALID_PARAMS);
6539
6540 rp.instance = cp->instance;
6541 rp.flags = cp->flags;
6542 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6543 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6544
6545 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6546 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6547
6548 return err;
6549}
6550
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006551static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006552 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006553 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006554 HCI_MGMT_NO_HDEV |
6555 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006556 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006557 HCI_MGMT_NO_HDEV |
6558 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006559 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006560 HCI_MGMT_NO_HDEV |
6561 HCI_MGMT_UNTRUSTED },
6562 { read_controller_info, MGMT_READ_INFO_SIZE,
6563 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006564 { set_powered, MGMT_SETTING_SIZE },
6565 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6566 { set_connectable, MGMT_SETTING_SIZE },
6567 { set_fast_connectable, MGMT_SETTING_SIZE },
6568 { set_bondable, MGMT_SETTING_SIZE },
6569 { set_link_security, MGMT_SETTING_SIZE },
6570 { set_ssp, MGMT_SETTING_SIZE },
6571 { set_hs, MGMT_SETTING_SIZE },
6572 { set_le, MGMT_SETTING_SIZE },
6573 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6574 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6575 { add_uuid, MGMT_ADD_UUID_SIZE },
6576 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006577 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6578 HCI_MGMT_VAR_LEN },
6579 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6580 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006581 { disconnect, MGMT_DISCONNECT_SIZE },
6582 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6583 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6584 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6585 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6586 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6587 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6588 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6589 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6590 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6591 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6592 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006593 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6594 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6595 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006596 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6597 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6598 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6599 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6600 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6601 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6602 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6603 { set_advertising, MGMT_SETTING_SIZE },
6604 { set_bredr, MGMT_SETTING_SIZE },
6605 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6606 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6607 { set_secure_conn, MGMT_SETTING_SIZE },
6608 { set_debug_keys, MGMT_SETTING_SIZE },
6609 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006610 { load_irks, MGMT_LOAD_IRKS_SIZE,
6611 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006612 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6613 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6614 { add_device, MGMT_ADD_DEVICE_SIZE },
6615 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006616 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6617 HCI_MGMT_VAR_LEN },
6618 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006619 HCI_MGMT_NO_HDEV |
6620 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006621 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006622 HCI_MGMT_UNCONFIGURED |
6623 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006624 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6625 HCI_MGMT_UNCONFIGURED },
6626 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6627 HCI_MGMT_UNCONFIGURED },
6628 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6629 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006630 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006631 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006632 HCI_MGMT_NO_HDEV |
6633 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006634 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006635 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6636 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006637 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006638 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006639};
6640
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006641void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006642{
Marcel Holtmannced85542015-03-14 19:27:56 -07006643 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006644
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006645 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6646 return;
6647
Marcel Holtmannf9207332015-03-14 19:27:55 -07006648 switch (hdev->dev_type) {
6649 case HCI_BREDR:
6650 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6651 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6652 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006653 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006654 } else {
6655 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6656 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006657 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006658 }
6659 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006660 case HCI_AMP:
6661 ev.type = 0x02;
6662 break;
6663 default:
6664 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006665 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006666
6667 ev.bus = hdev->bus;
6668
6669 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6670 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006671}
6672
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006673void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006674{
Marcel Holtmannced85542015-03-14 19:27:56 -07006675 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006676 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006677
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006678 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6679 return;
6680
Marcel Holtmannf9207332015-03-14 19:27:55 -07006681 switch (hdev->dev_type) {
6682 case HCI_BREDR:
6683 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006684
Marcel Holtmannf9207332015-03-14 19:27:55 -07006685 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6686 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6687 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006688 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006689 } else {
6690 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6691 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006692 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006693 }
6694 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006695 case HCI_AMP:
6696 ev.type = 0x02;
6697 break;
6698 default:
6699 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006700 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006701
6702 ev.bus = hdev->bus;
6703
6704 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6705 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006706}
6707
Andre Guedes6046dc32014-02-26 20:21:51 -03006708/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006709static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006710{
6711 struct hci_conn_params *p;
6712
6713 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006714 /* Needed for AUTO_OFF case where might not "really"
6715 * have been powered off.
6716 */
6717 list_del_init(&p->action);
6718
6719 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006720 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006721 case HCI_AUTO_CONN_ALWAYS:
6722 list_add(&p->action, &hdev->pend_le_conns);
6723 break;
6724 case HCI_AUTO_CONN_REPORT:
6725 list_add(&p->action, &hdev->pend_le_reports);
6726 break;
6727 default:
6728 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006729 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006730 }
6731}
6732
Marcel Holtmann1904a852015-01-11 13:50:44 -08006733static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006734{
6735 struct cmd_lookup match = { NULL, hdev };
6736
6737 BT_DBG("status 0x%02x", status);
6738
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006739 if (!status) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006740 restart_le_actions(hdev);
6741 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006742 }
6743
Johan Hedberg229ab392013-03-15 17:06:53 -05006744 hci_dev_lock(hdev);
6745
6746 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6747
6748 new_settings(hdev, match.sk);
6749
6750 hci_dev_unlock(hdev);
6751
6752 if (match.sk)
6753 sock_put(match.sk);
6754}
6755
Johan Hedberg70da6242013-03-15 17:06:51 -05006756static int powered_update_hci(struct hci_dev *hdev)
6757{
Johan Hedberg890ea892013-03-15 17:06:52 -05006758 struct hci_request req;
Florian Grandel320b3bf2015-06-18 03:16:49 +02006759 struct adv_info *adv_instance;
Johan Hedberg70da6242013-03-15 17:06:51 -05006760 u8 link_sec;
6761
Johan Hedberg890ea892013-03-15 17:06:52 -05006762 hci_req_init(&req, hdev);
6763
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006764 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006765 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006766 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006767
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006768 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006769
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006770 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6771 u8 support = 0x01;
6772
6773 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6774 sizeof(support), &support);
6775 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006776 }
6777
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006778 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006779 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006780 struct hci_cp_write_le_host_supported cp;
6781
Marcel Holtmann32226e42014-07-24 20:04:16 +02006782 cp.le = 0x01;
6783 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006784
6785 /* Check first if we already have the right
6786 * host state (host features set)
6787 */
6788 if (cp.le != lmp_host_le_capable(hdev) ||
6789 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006790 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6791 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006792 }
6793
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006794 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006795 /* Make sure the controller has a good default for
6796 * advertising data. This also applies to the case
6797 * where BR/EDR was toggled during the AUTO_OFF phase.
6798 */
Florian Grandel320b3bf2015-06-18 03:16:49 +02006799 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
6800 (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6801 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
Johan Hedbergf2252572015-11-18 12:49:20 +02006802 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
6803 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006804 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006805
Florian Grandel320b3bf2015-06-18 03:16:49 +02006806 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6807 hdev->cur_adv_instance == 0x00 &&
6808 !list_empty(&hdev->adv_instances)) {
6809 adv_instance = list_first_entry(&hdev->adv_instances,
6810 struct adv_info, list);
6811 hdev->cur_adv_instance = adv_instance->instance;
6812 }
6813
6814 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergf2252572015-11-18 12:49:20 +02006815 __hci_req_enable_advertising(&req);
Florian Grandel320b3bf2015-06-18 03:16:49 +02006816 else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6817 hdev->cur_adv_instance)
Johan Hedbergf2252572015-11-18 12:49:20 +02006818 __hci_req_schedule_adv_instance(&req,
6819 hdev->cur_adv_instance,
6820 true);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006821 }
6822
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006823 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006824 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006825 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6826 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006827
6828 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006829 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006830 write_fast_connectable(&req, true);
6831 else
6832 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006833 __hci_req_update_scan(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02006834 __hci_req_update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006835 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006836 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006837 }
6838
Johan Hedberg229ab392013-03-15 17:06:53 -05006839 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006840}
6841
Johan Hedberg744cf192011-11-08 20:40:14 +02006842int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006843{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006844 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006845 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006846 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006847
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006848 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006849 return 0;
6850
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006851 if (powered) {
Andrzej Kaczmareke59a5542015-11-22 21:42:21 +01006852 /* Register the available SMP channels (BR/EDR and LE) only
6853 * when successfully powering on the controller. This late
6854 * registration is required so that LE SMP can clearly
6855 * decide if the public address or static address is used.
6856 */
6857 smp_register(hdev);
6858
Johan Hedberg229ab392013-03-15 17:06:53 -05006859 if (powered_update_hci(hdev) == 0)
6860 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006861
Johan Hedberg229ab392013-03-15 17:06:53 -05006862 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6863 &match);
6864 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006865 }
6866
Johan Hedberg229ab392013-03-15 17:06:53 -05006867 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006868
6869 /* If the power off is because of hdev unregistration let
6870 * use the appropriate INVALID_INDEX status. Otherwise use
6871 * NOT_POWERED. We cover both scenarios here since later in
6872 * mgmt_index_removed() any hci_conn callbacks will have already
6873 * been triggered, potentially causing misleading DISCONNECTED
6874 * status responses.
6875 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006876 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006877 status = MGMT_STATUS_INVALID_INDEX;
6878 else
6879 status = MGMT_STATUS_NOT_POWERED;
6880
6881 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006882
6883 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006884 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6885 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006886
6887new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006888 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006889
6890 if (match.sk)
6891 sock_put(match.sk);
6892
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006893 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006894}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006895
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006896void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006897{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006898 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006899 u8 status;
6900
Johan Hedberg333ae952015-03-17 13:48:47 +02006901 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006902 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006903 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006904
6905 if (err == -ERFKILL)
6906 status = MGMT_STATUS_RFKILLED;
6907 else
6908 status = MGMT_STATUS_FAILED;
6909
Johan Hedberga69e8372015-03-06 21:08:53 +02006910 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006911
6912 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006913}
6914
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006915void mgmt_discoverable_timeout(struct hci_dev *hdev)
6916{
6917 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006918
6919 hci_dev_lock(hdev);
6920
6921 /* When discoverable timeout triggers, then just make sure
6922 * the limited discoverable flag is cleared. Even in the case
6923 * of a timeout triggered from general discoverable, it is
6924 * safe to unconditionally clear the flag.
6925 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006926 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
6927 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006928
6929 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006930 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03006931 u8 scan = SCAN_PAGE;
6932 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
6933 sizeof(scan), &scan);
6934 }
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02006935 __hci_req_update_class(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07006936
6937 /* Advertising instances don't use the global discoverable setting, so
6938 * only update AD if advertising was enabled using Set Advertising.
6939 */
6940 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergf2252572015-11-18 12:49:20 +02006941 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Arman Uguray24b4f382015-03-23 15:57:12 -07006942
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006943 hci_req_run(&req, NULL);
6944
6945 hdev->discov_timeout = 0;
6946
Johan Hedberg9a43e252013-10-20 19:00:07 +03006947 new_settings(hdev, NULL);
6948
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006949 hci_dev_unlock(hdev);
6950}
6951
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006952void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6953 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006954{
Johan Hedberg86742e12011-11-07 23:13:38 +02006955 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006956
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006957 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006958
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006959 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006960 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006961 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006962 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006963 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006964 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006965
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006966 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006967}
Johan Hedbergf7520542011-01-20 12:34:39 +02006968
Johan Hedbergd7b25452014-05-23 13:19:53 +03006969static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6970{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006971 switch (ltk->type) {
6972 case SMP_LTK:
6973 case SMP_LTK_SLAVE:
6974 if (ltk->authenticated)
6975 return MGMT_LTK_AUTHENTICATED;
6976 return MGMT_LTK_UNAUTHENTICATED;
6977 case SMP_LTK_P256:
6978 if (ltk->authenticated)
6979 return MGMT_LTK_P256_AUTH;
6980 return MGMT_LTK_P256_UNAUTH;
6981 case SMP_LTK_P256_DEBUG:
6982 return MGMT_LTK_P256_DEBUG;
6983 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006984
6985 return MGMT_LTK_UNAUTHENTICATED;
6986}
6987
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006988void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006989{
6990 struct mgmt_ev_new_long_term_key ev;
6991
6992 memset(&ev, 0, sizeof(ev));
6993
Marcel Holtmann5192d302014-02-19 17:11:58 -08006994 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006995 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006996 * to store long term keys. Their addresses will change the
6997 * next time around.
6998 *
6999 * Only when a remote device provides an identity address
7000 * make sure the long term key is stored. If the remote
7001 * identity is known, the long term keys are internally
7002 * mapped to the identity address. So allow static random
7003 * and public addresses here.
7004 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007005 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7006 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7007 ev.store_hint = 0x00;
7008 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007009 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007010
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007011 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007012 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007013 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007014 ev.key.enc_size = key->enc_size;
7015 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007016 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007017
Johan Hedberg2ceba532014-06-16 19:25:16 +03007018 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007019 ev.key.master = 1;
7020
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007021 /* Make sure we copy only the significant bytes based on the
7022 * encryption key size, and set the rest of the value to zeroes.
7023 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02007024 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007025 memset(ev.key.val + key->enc_size, 0,
7026 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007027
Marcel Holtmann083368f2013-10-15 14:26:29 -07007028 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007029}
7030
Johan Hedbergcad20c22015-10-12 13:36:19 +02007031void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02007032{
7033 struct mgmt_ev_new_irk ev;
7034
7035 memset(&ev, 0, sizeof(ev));
7036
Johan Hedbergcad20c22015-10-12 13:36:19 +02007037 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007038
Johan Hedberg95fbac82014-02-19 15:18:31 +02007039 bacpy(&ev.rpa, &irk->rpa);
7040 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7041 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7042 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7043
7044 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7045}
7046
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007047void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7048 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007049{
7050 struct mgmt_ev_new_csrk ev;
7051
7052 memset(&ev, 0, sizeof(ev));
7053
7054 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007055 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007056 * to store signature resolving keys. Their addresses will change
7057 * the next time around.
7058 *
7059 * Only when a remote device provides an identity address
7060 * make sure the signature resolving key is stored. So allow
7061 * static random and public addresses here.
7062 */
7063 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7064 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7065 ev.store_hint = 0x00;
7066 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007067 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007068
7069 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7070 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007071 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007072 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7073
7074 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7075}
7076
Andre Guedesffb5a8272014-07-01 18:10:11 -03007077void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007078 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7079 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007080{
7081 struct mgmt_ev_new_conn_param ev;
7082
Johan Hedbergc103aea2014-07-02 17:37:34 +03007083 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7084 return;
7085
Andre Guedesffb5a8272014-07-01 18:10:11 -03007086 memset(&ev, 0, sizeof(ev));
7087 bacpy(&ev.addr.bdaddr, bdaddr);
7088 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007089 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007090 ev.min_interval = cpu_to_le16(min_interval);
7091 ev.max_interval = cpu_to_le16(max_interval);
7092 ev.latency = cpu_to_le16(latency);
7093 ev.timeout = cpu_to_le16(timeout);
7094
7095 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7096}
7097
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007098void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7099 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007100{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007101 char buf[512];
7102 struct mgmt_ev_device_connected *ev = (void *) buf;
7103 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007104
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007105 bacpy(&ev->addr.bdaddr, &conn->dst);
7106 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007107
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007108 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007109
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007110 /* We must ensure that the EIR Data fields are ordered and
7111 * unique. Keep it simple for now and avoid the problem by not
7112 * adding any BR/EDR data to the LE adv.
7113 */
7114 if (conn->le_adv_data_len > 0) {
7115 memcpy(&ev->eir[eir_len],
7116 conn->le_adv_data, conn->le_adv_data_len);
7117 eir_len = conn->le_adv_data_len;
7118 } else {
7119 if (name_len > 0)
7120 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7121 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007122
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007123 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007124 eir_len = eir_append_data(ev->eir, eir_len,
7125 EIR_CLASS_OF_DEV,
7126 conn->dev_class, 3);
7127 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007128
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007129 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007130
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007131 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7132 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007133}
7134
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007135static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007136{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007137 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007138
Johan Hedbergf5818c22014-12-05 13:36:02 +02007139 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007140
7141 *sk = cmd->sk;
7142 sock_hold(*sk);
7143
Johan Hedberga664b5b2011-02-19 12:06:02 -03007144 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007145}
7146
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007147static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007148{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007149 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007150 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007151
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007152 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7153
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007154 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007155 mgmt_pending_remove(cmd);
7156}
7157
Johan Hedberg84c61d92014-08-01 11:13:30 +03007158bool mgmt_powering_down(struct hci_dev *hdev)
7159{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007160 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007161 struct mgmt_mode *cp;
7162
Johan Hedberg333ae952015-03-17 13:48:47 +02007163 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007164 if (!cmd)
7165 return false;
7166
7167 cp = cmd->param;
7168 if (!cp->val)
7169 return true;
7170
7171 return false;
7172}
7173
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007174void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007175 u8 link_type, u8 addr_type, u8 reason,
7176 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007177{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007178 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007179 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007180
Johan Hedberg84c61d92014-08-01 11:13:30 +03007181 /* The connection is still in hci_conn_hash so test for 1
7182 * instead of 0 to know if this is the last one.
7183 */
7184 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7185 cancel_delayed_work(&hdev->power_off);
7186 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007187 }
7188
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007189 if (!mgmt_connected)
7190 return;
7191
Andre Guedes57eb7762013-10-30 19:01:41 -03007192 if (link_type != ACL_LINK && link_type != LE_LINK)
7193 return;
7194
Johan Hedberg744cf192011-11-08 20:40:14 +02007195 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007196
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007197 bacpy(&ev.addr.bdaddr, bdaddr);
7198 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7199 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007200
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007201 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007202
7203 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007204 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007205
Johan Hedberg124f6e32012-02-09 13:50:12 +02007206 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007207 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007208}
7209
Marcel Holtmann78929242013-10-06 23:55:47 -07007210void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7211 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007212{
Andre Guedes3655bba2013-10-30 19:01:40 -03007213 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7214 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007215 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007216
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007217 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7218 hdev);
7219
Johan Hedberg333ae952015-03-17 13:48:47 +02007220 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007221 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007222 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007223
Andre Guedes3655bba2013-10-30 19:01:40 -03007224 cp = cmd->param;
7225
7226 if (bacmp(bdaddr, &cp->addr.bdaddr))
7227 return;
7228
7229 if (cp->addr.type != bdaddr_type)
7230 return;
7231
Johan Hedbergf5818c22014-12-05 13:36:02 +02007232 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007233 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007234}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007235
Marcel Holtmann445608d2013-10-06 23:55:48 -07007236void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7237 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007238{
7239 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007240
Johan Hedberg84c61d92014-08-01 11:13:30 +03007241 /* The connection is still in hci_conn_hash so test for 1
7242 * instead of 0 to know if this is the last one.
7243 */
7244 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7245 cancel_delayed_work(&hdev->power_off);
7246 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007247 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007248
Johan Hedberg4c659c32011-11-07 23:13:39 +02007249 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007250 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007251 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007252
Marcel Holtmann445608d2013-10-06 23:55:48 -07007253 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007254}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007255
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007256void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007257{
7258 struct mgmt_ev_pin_code_request ev;
7259
Johan Hedbergd8457692012-02-17 14:24:57 +02007260 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007261 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007262 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007263
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007264 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007265}
7266
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007267void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7268 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007269{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007270 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007271
Johan Hedberg333ae952015-03-17 13:48:47 +02007272 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007273 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007274 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007275
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007276 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007277 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007278}
7279
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007280void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7281 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007282{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007283 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007284
Johan Hedberg333ae952015-03-17 13:48:47 +02007285 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007286 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007287 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007288
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007289 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007290 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007291}
Johan Hedberga5c29682011-02-19 12:05:57 -03007292
Johan Hedberg744cf192011-11-08 20:40:14 +02007293int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007294 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007295 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007296{
7297 struct mgmt_ev_user_confirm_request ev;
7298
Johan Hedberg744cf192011-11-08 20:40:14 +02007299 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007300
Johan Hedberg272d90d2012-02-09 15:26:12 +02007301 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007302 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007303 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007304 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007305
Johan Hedberg744cf192011-11-08 20:40:14 +02007306 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007307 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007308}
7309
Johan Hedberg272d90d2012-02-09 15:26:12 +02007310int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007311 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007312{
7313 struct mgmt_ev_user_passkey_request ev;
7314
7315 BT_DBG("%s", hdev->name);
7316
Johan Hedberg272d90d2012-02-09 15:26:12 +02007317 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007318 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007319
7320 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007321 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007322}
7323
Brian Gix0df4c182011-11-16 13:53:13 -08007324static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007325 u8 link_type, u8 addr_type, u8 status,
7326 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007327{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007328 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007329
Johan Hedberg333ae952015-03-17 13:48:47 +02007330 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007331 if (!cmd)
7332 return -ENOENT;
7333
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007334 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007335 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007336
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007337 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007338}
7339
Johan Hedberg744cf192011-11-08 20:40:14 +02007340int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007341 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007342{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007343 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007344 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007345}
7346
Johan Hedberg272d90d2012-02-09 15:26:12 +02007347int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007348 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007349{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007350 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007351 status,
7352 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007353}
Johan Hedberg2a611692011-02-19 12:06:00 -03007354
Brian Gix604086b2011-11-23 08:28:33 -08007355int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007356 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007357{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007358 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007359 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007360}
7361
Johan Hedberg272d90d2012-02-09 15:26:12 +02007362int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007363 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007364{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007365 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007366 status,
7367 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007368}
7369
Johan Hedberg92a25252012-09-06 18:39:26 +03007370int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7371 u8 link_type, u8 addr_type, u32 passkey,
7372 u8 entered)
7373{
7374 struct mgmt_ev_passkey_notify ev;
7375
7376 BT_DBG("%s", hdev->name);
7377
7378 bacpy(&ev.addr.bdaddr, bdaddr);
7379 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7380 ev.passkey = __cpu_to_le32(passkey);
7381 ev.entered = entered;
7382
7383 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7384}
7385
Johan Hedberge1e930f2014-09-08 17:09:49 -07007386void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007387{
7388 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007389 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007390 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007391
Johan Hedberge1e930f2014-09-08 17:09:49 -07007392 bacpy(&ev.addr.bdaddr, &conn->dst);
7393 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7394 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007395
Johan Hedberge1e930f2014-09-08 17:09:49 -07007396 cmd = find_pairing(conn);
7397
7398 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7399 cmd ? cmd->sk : NULL);
7400
Johan Hedberga511b352014-12-11 21:45:45 +02007401 if (cmd) {
7402 cmd->cmd_complete(cmd, status);
7403 mgmt_pending_remove(cmd);
7404 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007405}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007406
Marcel Holtmann464996a2013-10-15 14:26:24 -07007407void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007408{
7409 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007410 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007411
7412 if (status) {
7413 u8 mgmt_err = mgmt_status(status);
7414 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007415 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007416 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007417 }
7418
Marcel Holtmann464996a2013-10-15 14:26:24 -07007419 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007420 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007421 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007422 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007423
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007424 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007425 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007426
Johan Hedberg47990ea2012-02-22 11:58:37 +02007427 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007428 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007429
7430 if (match.sk)
7431 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007432}
7433
Johan Hedberg890ea892013-03-15 17:06:52 -05007434static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007435{
Johan Hedberg890ea892013-03-15 17:06:52 -05007436 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007437 struct hci_cp_write_eir cp;
7438
Johan Hedberg976eb202012-10-24 21:12:01 +03007439 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007440 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007441
Johan Hedbergc80da272012-02-22 15:38:48 +02007442 memset(hdev->eir, 0, sizeof(hdev->eir));
7443
Johan Hedbergcacaf522012-02-21 00:52:42 +02007444 memset(&cp, 0, sizeof(cp));
7445
Johan Hedberg890ea892013-03-15 17:06:52 -05007446 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007447}
7448
Marcel Holtmann3e248562013-10-15 14:26:25 -07007449void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007450{
7451 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007452 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007453 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007454
7455 if (status) {
7456 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007457
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007458 if (enable && hci_dev_test_and_clear_flag(hdev,
7459 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007460 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007461 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007462 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007463
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007464 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7465 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007466 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007467 }
7468
7469 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007470 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007471 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007472 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007473 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007474 changed = hci_dev_test_and_clear_flag(hdev,
7475 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007476 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007477 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007478 }
7479
7480 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7481
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007482 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007483 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007484
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007485 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007486 sock_put(match.sk);
7487
Johan Hedberg890ea892013-03-15 17:06:52 -05007488 hci_req_init(&req, hdev);
7489
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007490 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7491 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007492 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7493 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007494 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007495 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007496 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007497 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007498
7499 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007500}
7501
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007502static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007503{
7504 struct cmd_lookup *match = data;
7505
Johan Hedberg90e70452012-02-23 23:09:40 +02007506 if (match->sk == NULL) {
7507 match->sk = cmd->sk;
7508 sock_hold(match->sk);
7509 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007510}
7511
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007512void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7513 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007514{
Johan Hedberg90e70452012-02-23 23:09:40 +02007515 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007516
Johan Hedberg92da6092013-03-15 17:06:55 -05007517 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7518 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7519 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007520
7521 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007522 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7523 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007524
7525 if (match.sk)
7526 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007527}
7528
Marcel Holtmann7667da32013-10-15 14:26:27 -07007529void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007530{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007531 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007532 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007533
Johan Hedberg13928972013-03-15 17:07:00 -05007534 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007535 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007536
7537 memset(&ev, 0, sizeof(ev));
7538 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007539 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007540
Johan Hedberg333ae952015-03-17 13:48:47 +02007541 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007542 if (!cmd) {
7543 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007544
Johan Hedberg13928972013-03-15 17:07:00 -05007545 /* If this is a HCI command related to powering on the
7546 * HCI dev don't send any mgmt signals.
7547 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007548 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007549 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007550 }
7551
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007552 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7553 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007554}
Szymon Jancc35938b2011-03-22 13:12:21 +01007555
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007556static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7557{
7558 int i;
7559
7560 for (i = 0; i < uuid_count; i++) {
7561 if (!memcmp(uuid, uuids[i], 16))
7562 return true;
7563 }
7564
7565 return false;
7566}
7567
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007568static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7569{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007570 u16 parsed = 0;
7571
7572 while (parsed < eir_len) {
7573 u8 field_len = eir[0];
7574 u8 uuid[16];
7575 int i;
7576
7577 if (field_len == 0)
7578 break;
7579
7580 if (eir_len - parsed < field_len + 1)
7581 break;
7582
7583 switch (eir[1]) {
7584 case EIR_UUID16_ALL:
7585 case EIR_UUID16_SOME:
7586 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007587 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007588 uuid[13] = eir[i + 3];
7589 uuid[12] = eir[i + 2];
7590 if (has_uuid(uuid, uuid_count, uuids))
7591 return true;
7592 }
7593 break;
7594 case EIR_UUID32_ALL:
7595 case EIR_UUID32_SOME:
7596 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007597 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007598 uuid[15] = eir[i + 5];
7599 uuid[14] = eir[i + 4];
7600 uuid[13] = eir[i + 3];
7601 uuid[12] = eir[i + 2];
7602 if (has_uuid(uuid, uuid_count, uuids))
7603 return true;
7604 }
7605 break;
7606 case EIR_UUID128_ALL:
7607 case EIR_UUID128_SOME:
7608 for (i = 0; i + 17 <= field_len; i += 16) {
7609 memcpy(uuid, eir + i + 2, 16);
7610 if (has_uuid(uuid, uuid_count, uuids))
7611 return true;
7612 }
7613 break;
7614 }
7615
7616 parsed += field_len + 1;
7617 eir += field_len + 1;
7618 }
7619
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007620 return false;
7621}
7622
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007623static void restart_le_scan(struct hci_dev *hdev)
7624{
7625 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007626 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007627 return;
7628
7629 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7630 hdev->discovery.scan_start +
7631 hdev->discovery.scan_duration))
7632 return;
7633
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007634 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007635 DISCOV_LE_RESTART_DELAY);
7636}
7637
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007638static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7639 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7640{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007641 /* If a RSSI threshold has been specified, and
7642 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7643 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7644 * is set, let it through for further processing, as we might need to
7645 * restart the scan.
7646 *
7647 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7648 * the results are also dropped.
7649 */
7650 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7651 (rssi == HCI_RSSI_INVALID ||
7652 (rssi < hdev->discovery.rssi &&
7653 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7654 return false;
7655
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007656 if (hdev->discovery.uuid_count != 0) {
7657 /* If a list of UUIDs is provided in filter, results with no
7658 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007659 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007660 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7661 hdev->discovery.uuids) &&
7662 !eir_has_uuids(scan_rsp, scan_rsp_len,
7663 hdev->discovery.uuid_count,
7664 hdev->discovery.uuids))
7665 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007666 }
7667
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007668 /* If duplicate filtering does not report RSSI changes, then restart
7669 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007670 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007671 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7672 restart_le_scan(hdev);
7673
7674 /* Validate RSSI value against the RSSI threshold once more. */
7675 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7676 rssi < hdev->discovery.rssi)
7677 return false;
7678 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007679
7680 return true;
7681}
7682
Marcel Holtmann901801b2013-10-06 23:55:51 -07007683void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007684 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7685 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007686{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007687 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007688 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007689 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007690
Johan Hedberg75ce2082014-07-02 22:42:01 +03007691 /* Don't send events for a non-kernel initiated discovery. With
7692 * LE one exception is if we have pend_le_reports > 0 in which
7693 * case we're doing passive scanning and want these events.
7694 */
7695 if (!hci_discovery_active(hdev)) {
7696 if (link_type == ACL_LINK)
7697 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007698 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007699 return;
7700 }
Andre Guedes12602d02013-04-30 15:29:40 -03007701
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007702 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007703 /* We are using service discovery */
7704 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7705 scan_rsp_len))
7706 return;
7707 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007708
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007709 /* Make sure that the buffer is big enough. The 5 extra bytes
7710 * are for the potential CoD field.
7711 */
7712 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007713 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007714
Johan Hedberg1dc06092012-01-15 21:01:23 +02007715 memset(buf, 0, sizeof(buf));
7716
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007717 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7718 * RSSI value was reported as 0 when not available. This behavior
7719 * is kept when using device discovery. This is required for full
7720 * backwards compatibility with the API.
7721 *
7722 * However when using service discovery, the value 127 will be
7723 * returned when the RSSI is not available.
7724 */
Szymon Janc91200e92015-01-22 16:57:05 +01007725 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7726 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007727 rssi = 0;
7728
Johan Hedberg841c5642014-07-07 12:45:54 +03007729 bacpy(&ev->addr.bdaddr, bdaddr);
7730 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007731 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007732 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007733
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007734 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007735 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007736 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007737
Johan Hedberg1dc06092012-01-15 21:01:23 +02007738 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7739 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007740 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007741
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007742 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007743 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007744 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007745
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007746 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7747 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007748
Marcel Holtmann901801b2013-10-06 23:55:51 -07007749 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007750}
Johan Hedberga88a9652011-03-30 13:18:12 +03007751
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007752void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7753 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007754{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007755 struct mgmt_ev_device_found *ev;
7756 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7757 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007758
Johan Hedbergb644ba32012-01-17 21:48:47 +02007759 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007760
Johan Hedbergb644ba32012-01-17 21:48:47 +02007761 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007762
Johan Hedbergb644ba32012-01-17 21:48:47 +02007763 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007764 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007765 ev->rssi = rssi;
7766
7767 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007768 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007769
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007770 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007771
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007772 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007773}
Johan Hedberg314b2382011-04-27 10:29:57 -04007774
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007775void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007776{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007777 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007778
Andre Guedes343fb142011-11-22 17:14:19 -03007779 BT_DBG("%s discovering %u", hdev->name, discovering);
7780
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007781 memset(&ev, 0, sizeof(ev));
7782 ev.type = hdev->discovery.type;
7783 ev.discovering = discovering;
7784
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007785 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007786}
Antti Julku5e762442011-08-25 16:48:02 +03007787
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007788static struct hci_mgmt_chan chan = {
7789 .channel = HCI_CHANNEL_CONTROL,
7790 .handler_count = ARRAY_SIZE(mgmt_handlers),
7791 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007792 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007793};
7794
7795int mgmt_init(void)
7796{
7797 return hci_mgmt_chan_register(&chan);
7798}
7799
7800void mgmt_exit(void)
7801{
7802 hci_mgmt_chan_unregister(&chan);
7803}