blob: 47fa16bffbe2ecd6128483f7aa910dbbcc47b3bd [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
Marcel Holtmannbeb1c212015-03-10 14:04:52 -070041#define MGMT_REVISION 9
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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200105};
106
107static const u16 mgmt_events[] = {
108 MGMT_EV_CONTROLLER_ERROR,
109 MGMT_EV_INDEX_ADDED,
110 MGMT_EV_INDEX_REMOVED,
111 MGMT_EV_NEW_SETTINGS,
112 MGMT_EV_CLASS_OF_DEV_CHANGED,
113 MGMT_EV_LOCAL_NAME_CHANGED,
114 MGMT_EV_NEW_LINK_KEY,
115 MGMT_EV_NEW_LONG_TERM_KEY,
116 MGMT_EV_DEVICE_CONNECTED,
117 MGMT_EV_DEVICE_DISCONNECTED,
118 MGMT_EV_CONNECT_FAILED,
119 MGMT_EV_PIN_CODE_REQUEST,
120 MGMT_EV_USER_CONFIRM_REQUEST,
121 MGMT_EV_USER_PASSKEY_REQUEST,
122 MGMT_EV_AUTH_FAILED,
123 MGMT_EV_DEVICE_FOUND,
124 MGMT_EV_DISCOVERING,
125 MGMT_EV_DEVICE_BLOCKED,
126 MGMT_EV_DEVICE_UNBLOCKED,
127 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300128 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800129 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700130 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200131 MGMT_EV_DEVICE_ADDED,
132 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300133 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200134 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200135 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200136 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700137 MGMT_EV_EXT_INDEX_ADDED,
138 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700139 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700140 MGMT_EV_ADVERTISING_ADDED,
141 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200142};
143
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700144static const u16 mgmt_untrusted_commands[] = {
145 MGMT_OP_READ_INDEX_LIST,
146 MGMT_OP_READ_INFO,
147 MGMT_OP_READ_UNCONF_INDEX_LIST,
148 MGMT_OP_READ_CONFIG_INFO,
149 MGMT_OP_READ_EXT_INDEX_LIST,
150};
151
152static const u16 mgmt_untrusted_events[] = {
153 MGMT_EV_INDEX_ADDED,
154 MGMT_EV_INDEX_REMOVED,
155 MGMT_EV_NEW_SETTINGS,
156 MGMT_EV_CLASS_OF_DEV_CHANGED,
157 MGMT_EV_LOCAL_NAME_CHANGED,
158 MGMT_EV_UNCONF_INDEX_ADDED,
159 MGMT_EV_UNCONF_INDEX_REMOVED,
160 MGMT_EV_NEW_CONFIG_OPTIONS,
161 MGMT_EV_EXT_INDEX_ADDED,
162 MGMT_EV_EXT_INDEX_REMOVED,
163};
164
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800165#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200166
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200167#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
168 "\x00\x00\x00\x00\x00\x00\x00\x00"
169
Johan Hedbergca69b792011-11-11 18:10:00 +0200170/* HCI to MGMT error code conversion table */
171static u8 mgmt_status_table[] = {
172 MGMT_STATUS_SUCCESS,
173 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
174 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
175 MGMT_STATUS_FAILED, /* Hardware Failure */
176 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
177 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200178 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200179 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
180 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
181 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
182 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
183 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
184 MGMT_STATUS_BUSY, /* Command Disallowed */
185 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
186 MGMT_STATUS_REJECTED, /* Rejected Security */
187 MGMT_STATUS_REJECTED, /* Rejected Personal */
188 MGMT_STATUS_TIMEOUT, /* Host Timeout */
189 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
190 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
191 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
192 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
193 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
194 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
195 MGMT_STATUS_BUSY, /* Repeated Attempts */
196 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
197 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
198 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
199 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
200 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
201 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
202 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
203 MGMT_STATUS_FAILED, /* Unspecified Error */
204 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
205 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
206 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
207 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
208 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
209 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
210 MGMT_STATUS_FAILED, /* Unit Link Key Used */
211 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
212 MGMT_STATUS_TIMEOUT, /* Instant Passed */
213 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
214 MGMT_STATUS_FAILED, /* Transaction Collision */
215 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
216 MGMT_STATUS_REJECTED, /* QoS Rejected */
217 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
218 MGMT_STATUS_REJECTED, /* Insufficient Security */
219 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
220 MGMT_STATUS_BUSY, /* Role Switch Pending */
221 MGMT_STATUS_FAILED, /* Slot Violation */
222 MGMT_STATUS_FAILED, /* Role Switch Failed */
223 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
224 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
225 MGMT_STATUS_BUSY, /* Host Busy Pairing */
226 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
227 MGMT_STATUS_BUSY, /* Controller Busy */
228 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
229 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
230 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
231 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
232 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
233};
234
235static u8 mgmt_status(u8 hci_status)
236{
237 if (hci_status < ARRAY_SIZE(mgmt_status_table))
238 return mgmt_status_table[hci_status];
239
240 return MGMT_STATUS_FAILED;
241}
242
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700243static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
244 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700245{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700246 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
247 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700248}
249
Marcel Holtmann72000df2015-03-16 16:11:21 -0700250static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
251 u16 len, int flag, struct sock *skip_sk)
252{
253 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
254 flag, skip_sk);
255}
256
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700257static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
258 u16 len, struct sock *skip_sk)
259{
260 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
261 HCI_MGMT_GENERIC_EVENTS, skip_sk);
262}
263
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200264static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
265 struct sock *skip_sk)
266{
267 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700268 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200269}
270
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
272 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200273{
274 struct mgmt_rp_read_version rp;
275
276 BT_DBG("sock %p", sk);
277
278 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700279 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200280
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200281 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
282 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200283}
284
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
286 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200287{
288 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700289 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200290 size_t rp_size;
291 int i, err;
292
293 BT_DBG("sock %p", sk);
294
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700295 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
296 num_commands = ARRAY_SIZE(mgmt_commands);
297 num_events = ARRAY_SIZE(mgmt_events);
298 } else {
299 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
300 num_events = ARRAY_SIZE(mgmt_untrusted_events);
301 }
302
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200303 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
304
305 rp = kmalloc(rp_size, GFP_KERNEL);
306 if (!rp)
307 return -ENOMEM;
308
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700309 rp->num_commands = cpu_to_le16(num_commands);
310 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200311
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700312 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
313 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200314
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700315 for (i = 0; i < num_commands; i++, opcode++)
316 put_unaligned_le16(mgmt_commands[i], opcode);
317
318 for (i = 0; i < num_events; i++, opcode++)
319 put_unaligned_le16(mgmt_events[i], opcode);
320 } else {
321 __le16 *opcode = rp->opcodes;
322
323 for (i = 0; i < num_commands; i++, opcode++)
324 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
325
326 for (i = 0; i < num_events; i++, opcode++)
327 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
328 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200329
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200330 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
331 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200332 kfree(rp);
333
334 return err;
335}
336
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300337static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
338 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200339{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200341 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200342 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300344 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345
346 BT_DBG("sock %p", sk);
347
348 read_lock(&hci_dev_list_lock);
349
350 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300351 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200352 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700353 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700354 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 }
356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 rp_len = sizeof(*rp) + (2 * count);
358 rp = kmalloc(rp_len, GFP_ATOMIC);
359 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100360 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200361 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100362 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363
Johan Hedberg476e44c2012-10-19 20:10:46 +0300364 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200365 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700366 if (hci_dev_test_flag(d, HCI_SETUP) ||
367 hci_dev_test_flag(d, HCI_CONFIG) ||
368 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200369 continue;
370
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200371 /* Devices marked as raw-only are neither configured
372 * nor unconfigured controllers.
373 */
374 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700375 continue;
376
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200377 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700378 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700379 rp->index[count++] = cpu_to_le16(d->id);
380 BT_DBG("Added hci%u", d->id);
381 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200382 }
383
Johan Hedberg476e44c2012-10-19 20:10:46 +0300384 rp->num_controllers = cpu_to_le16(count);
385 rp_len = sizeof(*rp) + (2 * count);
386
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200387 read_unlock(&hci_dev_list_lock);
388
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200389 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
390 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391
Johan Hedberga38528f2011-01-22 06:46:43 +0200392 kfree(rp);
393
394 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200395}
396
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200397static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
398 void *data, u16 data_len)
399{
400 struct mgmt_rp_read_unconf_index_list *rp;
401 struct hci_dev *d;
402 size_t rp_len;
403 u16 count;
404 int err;
405
406 BT_DBG("sock %p", sk);
407
408 read_lock(&hci_dev_list_lock);
409
410 count = 0;
411 list_for_each_entry(d, &hci_dev_list, list) {
412 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700413 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200414 count++;
415 }
416
417 rp_len = sizeof(*rp) + (2 * count);
418 rp = kmalloc(rp_len, GFP_ATOMIC);
419 if (!rp) {
420 read_unlock(&hci_dev_list_lock);
421 return -ENOMEM;
422 }
423
424 count = 0;
425 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700426 if (hci_dev_test_flag(d, HCI_SETUP) ||
427 hci_dev_test_flag(d, HCI_CONFIG) ||
428 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200429 continue;
430
431 /* Devices marked as raw-only are neither configured
432 * nor unconfigured controllers.
433 */
434 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
435 continue;
436
437 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700438 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200439 rp->index[count++] = cpu_to_le16(d->id);
440 BT_DBG("Added hci%u", d->id);
441 }
442 }
443
444 rp->num_controllers = cpu_to_le16(count);
445 rp_len = sizeof(*rp) + (2 * count);
446
447 read_unlock(&hci_dev_list_lock);
448
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200449 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
450 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200451
452 kfree(rp);
453
454 return err;
455}
456
Marcel Holtmann96f14742015-03-14 19:27:57 -0700457static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
458 void *data, u16 data_len)
459{
460 struct mgmt_rp_read_ext_index_list *rp;
461 struct hci_dev *d;
462 size_t rp_len;
463 u16 count;
464 int err;
465
466 BT_DBG("sock %p", sk);
467
468 read_lock(&hci_dev_list_lock);
469
470 count = 0;
471 list_for_each_entry(d, &hci_dev_list, list) {
472 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
473 count++;
474 }
475
476 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
477 rp = kmalloc(rp_len, GFP_ATOMIC);
478 if (!rp) {
479 read_unlock(&hci_dev_list_lock);
480 return -ENOMEM;
481 }
482
483 count = 0;
484 list_for_each_entry(d, &hci_dev_list, list) {
485 if (hci_dev_test_flag(d, HCI_SETUP) ||
486 hci_dev_test_flag(d, HCI_CONFIG) ||
487 hci_dev_test_flag(d, HCI_USER_CHANNEL))
488 continue;
489
490 /* Devices marked as raw-only are neither configured
491 * nor unconfigured controllers.
492 */
493 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
494 continue;
495
496 if (d->dev_type == HCI_BREDR) {
497 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
498 rp->entry[count].type = 0x01;
499 else
500 rp->entry[count].type = 0x00;
501 } else if (d->dev_type == HCI_AMP) {
502 rp->entry[count].type = 0x02;
503 } else {
504 continue;
505 }
506
507 rp->entry[count].bus = d->bus;
508 rp->entry[count++].index = cpu_to_le16(d->id);
509 BT_DBG("Added hci%u", d->id);
510 }
511
512 rp->num_controllers = cpu_to_le16(count);
513 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
514
515 read_unlock(&hci_dev_list_lock);
516
517 /* If this command is called at least once, then all the
518 * default index and unconfigured index events are disabled
519 * and from now on only extended index events are used.
520 */
521 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
522 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
523 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
524
525 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
526 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
527
528 kfree(rp);
529
530 return err;
531}
532
Marcel Holtmanndbece372014-07-04 18:11:55 +0200533static bool is_configured(struct hci_dev *hdev)
534{
535 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700536 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200537 return false;
538
539 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
540 !bacmp(&hdev->public_addr, BDADDR_ANY))
541 return false;
542
543 return true;
544}
545
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200546static __le32 get_missing_options(struct hci_dev *hdev)
547{
548 u32 options = 0;
549
Marcel Holtmanndbece372014-07-04 18:11:55 +0200550 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700551 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200552 options |= MGMT_OPTION_EXTERNAL_CONFIG;
553
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200554 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
555 !bacmp(&hdev->public_addr, BDADDR_ANY))
556 options |= MGMT_OPTION_PUBLIC_ADDRESS;
557
558 return cpu_to_le32(options);
559}
560
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200561static int new_options(struct hci_dev *hdev, struct sock *skip)
562{
563 __le32 options = get_missing_options(hdev);
564
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700565 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
566 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200567}
568
Marcel Holtmanndbece372014-07-04 18:11:55 +0200569static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
570{
571 __le32 options = get_missing_options(hdev);
572
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200573 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
574 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200575}
576
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200577static int read_config_info(struct sock *sk, struct hci_dev *hdev,
578 void *data, u16 data_len)
579{
580 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200581 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200582
583 BT_DBG("sock %p %s", sk, hdev->name);
584
585 hci_dev_lock(hdev);
586
587 memset(&rp, 0, sizeof(rp));
588 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200589
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200590 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
591 options |= MGMT_OPTION_EXTERNAL_CONFIG;
592
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200593 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200594 options |= MGMT_OPTION_PUBLIC_ADDRESS;
595
596 rp.supported_options = cpu_to_le32(options);
597 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200598
599 hci_dev_unlock(hdev);
600
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200601 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
602 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200603}
604
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200605static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200606{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200607 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200608
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200609 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300610 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800611 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300612 settings |= MGMT_SETTING_CONNECTABLE;
613 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200614
Andre Guedesed3fa312012-07-24 15:03:46 -0300615 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500616 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
617 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_BREDR;
619 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700620
621 if (lmp_ssp_capable(hdev)) {
622 settings |= MGMT_SETTING_SSP;
623 settings |= MGMT_SETTING_HS;
624 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800625
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800626 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800627 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700628 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100629
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300630 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200631 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300632 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300633 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200634 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800635 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300636 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200637
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200638 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
639 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200640 settings |= MGMT_SETTING_CONFIGURATION;
641
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200642 return settings;
643}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200644
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200645static u32 get_current_settings(struct hci_dev *hdev)
646{
647 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200648
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200649 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100650 settings |= MGMT_SETTING_POWERED;
651
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700652 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200653 settings |= MGMT_SETTING_CONNECTABLE;
654
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700655 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500656 settings |= MGMT_SETTING_FAST_CONNECTABLE;
657
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700658 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200659 settings |= MGMT_SETTING_DISCOVERABLE;
660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300662 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700664 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200665 settings |= MGMT_SETTING_BREDR;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200671 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200677 settings |= MGMT_SETTING_HS;
678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300680 settings |= MGMT_SETTING_ADVERTISING;
681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800683 settings |= MGMT_SETTING_SECURE_CONN;
684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800686 settings |= MGMT_SETTING_DEBUG_KEYS;
687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200689 settings |= MGMT_SETTING_PRIVACY;
690
Marcel Holtmann93690c22015-03-06 10:11:21 -0800691 /* The current setting for static address has two purposes. The
692 * first is to indicate if the static address will be used and
693 * the second is to indicate if it is actually set.
694 *
695 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700696 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800697 * address is actually used decides if the flag is set or not.
698 *
699 * For single mode LE only controllers and dual-mode controllers
700 * with BR/EDR disabled, the existence of the static address will
701 * be evaluated.
702 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700703 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700704 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800705 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
706 if (bacmp(&hdev->static_addr, BDADDR_ANY))
707 settings |= MGMT_SETTING_STATIC_ADDRESS;
708 }
709
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200710 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200711}
712
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300713#define PNP_INFO_SVCLASS_ID 0x1200
714
Johan Hedberg213202e2013-01-27 00:31:33 +0200715static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
716{
717 u8 *ptr = data, *uuids_start = NULL;
718 struct bt_uuid *uuid;
719
720 if (len < 4)
721 return ptr;
722
723 list_for_each_entry(uuid, &hdev->uuids, list) {
724 u16 uuid16;
725
726 if (uuid->size != 16)
727 continue;
728
729 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
730 if (uuid16 < 0x1100)
731 continue;
732
733 if (uuid16 == PNP_INFO_SVCLASS_ID)
734 continue;
735
736 if (!uuids_start) {
737 uuids_start = ptr;
738 uuids_start[0] = 1;
739 uuids_start[1] = EIR_UUID16_ALL;
740 ptr += 2;
741 }
742
743 /* Stop if not enough space to put next UUID */
744 if ((ptr - data) + sizeof(u16) > len) {
745 uuids_start[1] = EIR_UUID16_SOME;
746 break;
747 }
748
749 *ptr++ = (uuid16 & 0x00ff);
750 *ptr++ = (uuid16 & 0xff00) >> 8;
751 uuids_start[0] += sizeof(uuid16);
752 }
753
754 return ptr;
755}
756
Johan Hedbergcdf19632013-01-27 00:31:34 +0200757static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
758{
759 u8 *ptr = data, *uuids_start = NULL;
760 struct bt_uuid *uuid;
761
762 if (len < 6)
763 return ptr;
764
765 list_for_each_entry(uuid, &hdev->uuids, list) {
766 if (uuid->size != 32)
767 continue;
768
769 if (!uuids_start) {
770 uuids_start = ptr;
771 uuids_start[0] = 1;
772 uuids_start[1] = EIR_UUID32_ALL;
773 ptr += 2;
774 }
775
776 /* Stop if not enough space to put next UUID */
777 if ((ptr - data) + sizeof(u32) > len) {
778 uuids_start[1] = EIR_UUID32_SOME;
779 break;
780 }
781
782 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
783 ptr += sizeof(u32);
784 uuids_start[0] += sizeof(u32);
785 }
786
787 return ptr;
788}
789
Johan Hedbergc00d5752013-01-27 00:31:35 +0200790static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
791{
792 u8 *ptr = data, *uuids_start = NULL;
793 struct bt_uuid *uuid;
794
795 if (len < 18)
796 return ptr;
797
798 list_for_each_entry(uuid, &hdev->uuids, list) {
799 if (uuid->size != 128)
800 continue;
801
802 if (!uuids_start) {
803 uuids_start = ptr;
804 uuids_start[0] = 1;
805 uuids_start[1] = EIR_UUID128_ALL;
806 ptr += 2;
807 }
808
809 /* Stop if not enough space to put next UUID */
810 if ((ptr - data) + 16 > len) {
811 uuids_start[1] = EIR_UUID128_SOME;
812 break;
813 }
814
815 memcpy(ptr, uuid->uuid, 16);
816 ptr += 16;
817 uuids_start[0] += 16;
818 }
819
820 return ptr;
821}
822
Johan Hedberg333ae952015-03-17 13:48:47 +0200823static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
824{
825 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
826}
827
Johan Hedberg333ae952015-03-17 13:48:47 +0200828static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
829 struct hci_dev *hdev,
830 const void *data)
831{
832 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
833}
834
Florian Grandel91aa9bb2015-06-18 03:16:36 +0200835static u8 get_current_adv_instance(struct hci_dev *hdev)
836{
837 /* The "Set Advertising" setting supersedes the "Add Advertising"
838 * setting. Here we set the advertising data based on which
839 * setting was set. When neither apply, default to the global settings,
840 * represented by instance "0".
841 */
842 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
843 !hci_dev_test_flag(hdev, HCI_ADVERTISING))
Florian Grandel3ff37e62015-06-18 03:16:39 +0200844 return hdev->cur_adv_instance;
Florian Grandel91aa9bb2015-06-18 03:16:36 +0200845
846 return 0x00;
847}
848
Arman Uguray4117ed72015-03-23 15:57:14 -0700849static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700850{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700851 u8 ad_len = 0;
852 size_t name_len;
853
854 name_len = strlen(hdev->dev_name);
855 if (name_len > 0) {
856 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
857
858 if (name_len > max_len) {
859 name_len = max_len;
860 ptr[1] = EIR_NAME_SHORT;
861 } else
862 ptr[1] = EIR_NAME_COMPLETE;
863
864 ptr[0] = name_len + 1;
865
866 memcpy(ptr + 2, hdev->dev_name, name_len);
867
868 ad_len += (name_len + 2);
869 ptr += (name_len + 2);
870 }
871
872 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700873}
874
Arman Uguray4117ed72015-03-23 15:57:14 -0700875static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
876{
877 /* TODO: Set the appropriate entries based on advertising instance flags
878 * here once flags other than 0 are supported.
879 */
880 memcpy(ptr, hdev->adv_instance.scan_rsp_data,
881 hdev->adv_instance.scan_rsp_len);
882
883 return hdev->adv_instance.scan_rsp_len;
884}
885
Florian Grandelefae0022015-06-18 03:16:37 +0200886static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700887{
888 struct hci_dev *hdev = req->hdev;
889 struct hci_cp_le_set_scan_rsp_data cp;
890 u8 len;
891
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700892 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700893 return;
894
895 memset(&cp, 0, sizeof(cp));
896
Arman Uguray4117ed72015-03-23 15:57:14 -0700897 if (instance)
898 len = create_instance_scan_rsp_data(hdev, cp.data);
899 else
900 len = create_default_scan_rsp_data(hdev, cp.data);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700901
Johan Hedbergeb438b52013-10-16 15:31:07 +0300902 if (hdev->scan_rsp_data_len == len &&
Arman Uguray4117ed72015-03-23 15:57:14 -0700903 !memcmp(cp.data, hdev->scan_rsp_data, len))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700904 return;
905
Johan Hedbergeb438b52013-10-16 15:31:07 +0300906 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
907 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700908
909 cp.length = len;
910
911 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
912}
913
Arman Uguray4117ed72015-03-23 15:57:14 -0700914static void update_scan_rsp_data(struct hci_request *req)
915{
Florian Grandelefae0022015-06-18 03:16:37 +0200916 update_inst_scan_rsp_data(req, get_current_adv_instance(req->hdev));
Arman Uguray4117ed72015-03-23 15:57:14 -0700917}
918
Johan Hedberg9a43e252013-10-20 19:00:07 +0300919static u8 get_adv_discov_flags(struct hci_dev *hdev)
920{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200921 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300922
923 /* If there's a pending mgmt command the flags will not yet have
924 * their final values, so check for this first.
925 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200926 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300927 if (cmd) {
928 struct mgmt_mode *cp = cmd->param;
929 if (cp->val == 0x01)
930 return LE_AD_GENERAL;
931 else if (cp->val == 0x02)
932 return LE_AD_LIMITED;
933 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700934 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300935 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700936 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300937 return LE_AD_GENERAL;
938 }
939
940 return 0;
941}
942
Arman Uguraye7a685d2015-03-25 18:53:40 -0700943static bool get_connectable(struct hci_dev *hdev)
944{
945 struct mgmt_pending_cmd *cmd;
946
947 /* If there's a pending mgmt command the flag will not yet have
948 * it's final value, so check for this first.
949 */
950 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
951 if (cmd) {
952 struct mgmt_mode *cp = cmd->param;
953
954 return cp->val;
955 }
956
957 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
958}
959
960static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
961{
962 u32 flags;
Florian Grandel411b4122015-06-18 03:16:40 +0200963 struct adv_info *adv_instance;
Arman Uguraye7a685d2015-03-25 18:53:40 -0700964
Florian Grandelbea28e62015-06-18 03:16:41 +0200965 if (instance == 0x00) {
966 /* Instance 0 always manages the "Tx Power" and "Flags"
967 * fields
968 */
969 flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
Arman Uguraye7a685d2015-03-25 18:53:40 -0700970
Florian Grandelbea28e62015-06-18 03:16:41 +0200971 /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
972 * corresponds to the "connectable" instance flag.
973 */
974 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
975 flags |= MGMT_ADV_FLAG_CONNECTABLE;
Florian Grandel411b4122015-06-18 03:16:40 +0200976
Florian Grandelbea28e62015-06-18 03:16:41 +0200977 return flags;
Florian Grandel411b4122015-06-18 03:16:40 +0200978 }
Arman Uguraye7a685d2015-03-25 18:53:40 -0700979
Florian Grandelbea28e62015-06-18 03:16:41 +0200980 adv_instance = hci_find_adv_instance(hdev, instance);
Arman Uguraye7a685d2015-03-25 18:53:40 -0700981
Florian Grandelbea28e62015-06-18 03:16:41 +0200982 /* Return 0 when we got an invalid instance identifier. */
983 if (!adv_instance)
984 return 0;
Arman Uguraye7a685d2015-03-25 18:53:40 -0700985
Florian Grandelbea28e62015-06-18 03:16:41 +0200986 return adv_instance->flags;
Arman Uguraye7a685d2015-03-25 18:53:40 -0700987}
988
Arman Ugurayc7d48832015-03-28 12:38:59 -0700989static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
990{
991 /* Ignore instance 0 and other unsupported instances */
992 if (instance != 0x01)
993 return 0;
994
995 /* TODO: Take into account the "appearance" and "local-name" flags here.
996 * These are currently being ignored as they are not supported.
997 */
998 return hdev->adv_instance.scan_rsp_len;
999}
1000
Arman Ugurayfdf51782015-03-25 18:53:46 -07001001static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
1002{
1003 u8 ad_len = 0, flags = 0;
1004 u32 instance_flags = get_adv_instance_flags(hdev, instance);
1005
1006 /* The Add Advertising command allows userspace to set both the general
1007 * and limited discoverable flags.
1008 */
1009 if (instance_flags & MGMT_ADV_FLAG_DISCOV)
1010 flags |= LE_AD_GENERAL;
1011
1012 if (instance_flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
1013 flags |= LE_AD_LIMITED;
1014
1015 if (flags || (instance_flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) {
1016 /* If a discovery flag wasn't provided, simply use the global
1017 * settings.
1018 */
1019 if (!flags)
1020 flags |= get_adv_discov_flags(hdev);
1021
1022 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1023 flags |= LE_AD_NO_BREDR;
1024
1025 /* If flags would still be empty, then there is no need to
1026 * include the "Flags" AD field".
1027 */
1028 if (flags) {
1029 ptr[0] = 0x02;
1030 ptr[1] = EIR_FLAGS;
1031 ptr[2] = flags;
1032
1033 ad_len += 3;
1034 ptr += 3;
1035 }
1036 }
1037
Marcel Holtmann38c8af62015-04-03 13:23:12 -07001038 if (instance) {
1039 memcpy(ptr, hdev->adv_instance.adv_data,
1040 hdev->adv_instance.adv_data_len);
1041
1042 ad_len += hdev->adv_instance.adv_data_len;
1043 ptr += hdev->adv_instance.adv_data_len;
1044 }
1045
Arman Ugurayfdf51782015-03-25 18:53:46 -07001046 /* Provide Tx Power only if we can provide a valid value for it */
1047 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID &&
1048 (instance_flags & MGMT_ADV_FLAG_TX_POWER)) {
1049 ptr[0] = 0x02;
1050 ptr[1] = EIR_TX_POWER;
1051 ptr[2] = (u8)hdev->adv_tx_power;
1052
1053 ad_len += 3;
1054 ptr += 3;
1055 }
1056
Arman Ugurayfdf51782015-03-25 18:53:46 -07001057 return ad_len;
1058}
1059
Florian Grandelefae0022015-06-18 03:16:37 +02001060static void update_inst_adv_data(struct hci_request *req, u8 instance)
Arman Ugurayfdf51782015-03-25 18:53:46 -07001061{
1062 struct hci_dev *hdev = req->hdev;
1063 struct hci_cp_le_set_adv_data cp;
1064 u8 len;
1065
1066 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1067 return;
1068
1069 memset(&cp, 0, sizeof(cp));
1070
1071 len = create_instance_adv_data(hdev, instance, cp.data);
1072
1073 /* There's nothing to do if the data hasn't changed */
1074 if (hdev->adv_data_len == len &&
1075 memcmp(cp.data, hdev->adv_data, len) == 0)
1076 return;
1077
1078 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1079 hdev->adv_data_len = len;
1080
1081 cp.length = len;
1082
1083 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
1084}
1085
Arman Uguraye7a685d2015-03-25 18:53:40 -07001086static void update_adv_data(struct hci_request *req)
1087{
Florian Grandelefae0022015-06-18 03:16:37 +02001088 update_inst_adv_data(req, get_current_adv_instance(req->hdev));
Arman Uguray24b4f382015-03-23 15:57:12 -07001089}
1090
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001091int mgmt_update_adv_data(struct hci_dev *hdev)
1092{
1093 struct hci_request req;
1094
1095 hci_req_init(&req, hdev);
1096 update_adv_data(&req);
1097
1098 return hci_req_run(&req, NULL);
1099}
1100
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001101static void create_eir(struct hci_dev *hdev, u8 *data)
1102{
1103 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001104 size_t name_len;
1105
1106 name_len = strlen(hdev->dev_name);
1107
1108 if (name_len > 0) {
1109 /* EIR Data type */
1110 if (name_len > 48) {
1111 name_len = 48;
1112 ptr[1] = EIR_NAME_SHORT;
1113 } else
1114 ptr[1] = EIR_NAME_COMPLETE;
1115
1116 /* EIR Data length */
1117 ptr[0] = name_len + 1;
1118
1119 memcpy(ptr + 2, hdev->dev_name, name_len);
1120
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001121 ptr += (name_len + 2);
1122 }
1123
Johan Hedbergbbaf4442012-11-08 01:22:59 +01001124 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001125 ptr[0] = 2;
1126 ptr[1] = EIR_TX_POWER;
1127 ptr[2] = (u8) hdev->inq_tx_power;
1128
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001129 ptr += 3;
1130 }
1131
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001132 if (hdev->devid_source > 0) {
1133 ptr[0] = 9;
1134 ptr[1] = EIR_DEVICE_ID;
1135
1136 put_unaligned_le16(hdev->devid_source, ptr + 2);
1137 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
1138 put_unaligned_le16(hdev->devid_product, ptr + 6);
1139 put_unaligned_le16(hdev->devid_version, ptr + 8);
1140
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001141 ptr += 10;
1142 }
1143
Johan Hedberg213202e2013-01-27 00:31:33 +02001144 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +02001145 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +02001146 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001147}
1148
Johan Hedberg890ea892013-03-15 17:06:52 -05001149static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001150{
Johan Hedberg890ea892013-03-15 17:06:52 -05001151 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001152 struct hci_cp_write_eir cp;
1153
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001154 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001155 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001156
Johan Hedberg976eb202012-10-24 21:12:01 +03001157 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001158 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001159
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001160 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -05001161 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001162
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001163 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001164 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001165
1166 memset(&cp, 0, sizeof(cp));
1167
1168 create_eir(hdev, cp.data);
1169
1170 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001171 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001172
1173 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1174
Johan Hedberg890ea892013-03-15 17:06:52 -05001175 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001176}
1177
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001178static u8 get_service_classes(struct hci_dev *hdev)
1179{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001180 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001181 u8 val = 0;
1182
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001183 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001184 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001185
1186 return val;
1187}
1188
Johan Hedberg890ea892013-03-15 17:06:52 -05001189static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001190{
Johan Hedberg890ea892013-03-15 17:06:52 -05001191 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001192 u8 cod[3];
1193
1194 BT_DBG("%s", hdev->name);
1195
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001196 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001197 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001198
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001199 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001200 return;
1201
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001202 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001203 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001204
1205 cod[0] = hdev->minor_class;
1206 cod[1] = hdev->major_class;
1207 cod[2] = get_service_classes(hdev);
1208
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001209 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001210 cod[1] |= 0x20;
1211
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001212 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001213 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001214
Johan Hedberg890ea892013-03-15 17:06:52 -05001215 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001216}
1217
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001218static void disable_advertising(struct hci_request *req)
1219{
1220 u8 enable = 0x00;
1221
1222 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1223}
1224
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001225static void enable_advertising(struct hci_request *req)
1226{
1227 struct hci_dev *hdev = req->hdev;
1228 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001229 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001230 bool connectable;
Arman Uguraye7a685d2015-03-25 18:53:40 -07001231 u8 instance;
1232 u32 flags;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001233
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001234 if (hci_conn_num(hdev, LE_LINK) > 0)
1235 return;
1236
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001237 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001238 disable_advertising(req);
1239
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001240 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001241 * hci_update_random_address knows that it's safe to go ahead
1242 * and write a new random address. The flag will be set back on
1243 * as soon as the SET_ADV_ENABLE HCI command completes.
1244 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001245 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001246
Arman Uguraye7a685d2015-03-25 18:53:40 -07001247 instance = get_current_adv_instance(hdev);
1248 flags = get_adv_instance_flags(hdev, instance);
Arman Ugurayfaccb952015-03-28 12:38:58 -07001249
1250 /* If the "connectable" instance flag was not set, then choose between
1251 * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
1252 */
1253 connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
1254 get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001255
Johan Hedberga4858cb2014-02-25 19:56:31 +02001256 /* Set require_privacy to true only when non-connectable
1257 * advertising is used. In that case it is fine to use a
1258 * non-resolvable private address.
1259 */
1260 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001261 return;
1262
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001263 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001264 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1265 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Arman Ugurayc7d48832015-03-28 12:38:59 -07001266
1267 if (connectable)
1268 cp.type = LE_ADV_IND;
1269 else if (get_adv_instance_scan_rsp_len(hdev, instance))
1270 cp.type = LE_ADV_SCAN_IND;
1271 else
1272 cp.type = LE_ADV_NONCONN_IND;
1273
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001274 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001275 cp.channel_map = hdev->le_adv_channel_map;
1276
1277 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1278
1279 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1280}
1281
Johan Hedberg7d785252011-12-15 00:47:39 +02001282static void service_cache_off(struct work_struct *work)
1283{
1284 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001285 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001286 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001287
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001288 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001289 return;
1290
Johan Hedberg890ea892013-03-15 17:06:52 -05001291 hci_req_init(&req, hdev);
1292
Johan Hedberg7d785252011-12-15 00:47:39 +02001293 hci_dev_lock(hdev);
1294
Johan Hedberg890ea892013-03-15 17:06:52 -05001295 update_eir(&req);
1296 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001297
1298 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001299
1300 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001301}
1302
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001303static void rpa_expired(struct work_struct *work)
1304{
1305 struct hci_dev *hdev = container_of(work, struct hci_dev,
1306 rpa_expired.work);
1307 struct hci_request req;
1308
1309 BT_DBG("");
1310
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001311 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001312
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001313 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001314 return;
1315
1316 /* The generation of a new RPA and programming it into the
1317 * controller happens in the enable_advertising() function.
1318 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001319 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001320 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001321 hci_req_run(&req, NULL);
1322}
1323
Johan Hedberg6a919082012-02-28 06:17:26 +02001324static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001325{
Marcel Holtmann238be782015-03-13 02:11:06 -07001326 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001327 return;
1328
Johan Hedberg4f87da82012-03-02 19:55:56 +02001329 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001330 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001331
Johan Hedberg4f87da82012-03-02 19:55:56 +02001332 /* Non-mgmt controlled devices get this bit set
1333 * implicitly so that pairing works for them, however
1334 * for mgmt we require user-space to explicitly enable
1335 * it
1336 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001337 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001338}
1339
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001340static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001341 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001342{
1343 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001344
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001345 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001346
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001347 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001348
Johan Hedberg03811012010-12-08 00:21:06 +02001349 memset(&rp, 0, sizeof(rp));
1350
Johan Hedberg03811012010-12-08 00:21:06 +02001351 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001352
1353 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001354 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001355
1356 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1357 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1358
1359 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001360
1361 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001362 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001363
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001364 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001365
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001366 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1367 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001368}
1369
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001370static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001371{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001372 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001373
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001374 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1375 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001376}
1377
Marcel Holtmann1904a852015-01-11 13:50:44 -08001378static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001379{
1380 BT_DBG("%s status 0x%02x", hdev->name, status);
1381
Johan Hedberga3172b72014-02-28 09:33:44 +02001382 if (hci_conn_count(hdev) == 0) {
1383 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001384 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001385 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001386}
1387
Johan Hedberg23a48092014-07-08 16:05:06 +03001388static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001389{
1390 struct hci_dev *hdev = req->hdev;
1391 struct hci_cp_remote_name_req_cancel cp;
1392 struct inquiry_entry *e;
1393
1394 switch (hdev->discovery.state) {
1395 case DISCOVERY_FINDING:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001396 if (test_bit(HCI_INQUIRY, &hdev->flags))
Johan Hedberg21a60d32014-06-10 14:05:58 +03001397 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001398
1399 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001400 cancel_delayed_work(&hdev->le_scan_disable);
1401 hci_req_add_le_scan_disable(req);
1402 }
1403
Johan Hedberg23a48092014-07-08 16:05:06 +03001404 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001405
1406 case DISCOVERY_RESOLVING:
1407 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1408 NAME_PENDING);
1409 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001410 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001411
1412 bacpy(&cp.bdaddr, &e->data.bdaddr);
1413 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1414 &cp);
1415
Johan Hedberg23a48092014-07-08 16:05:06 +03001416 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001417
1418 default:
1419 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001420 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001421 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001422 return true;
1423 }
1424
Johan Hedberg21a60d32014-06-10 14:05:58 +03001425 break;
1426 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001427
1428 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001429}
1430
Arman Uguray912098a2015-03-23 15:57:15 -07001431static void advertising_added(struct sock *sk, struct hci_dev *hdev,
1432 u8 instance)
1433{
1434 struct mgmt_ev_advertising_added ev;
1435
1436 ev.instance = instance;
1437
1438 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1439}
1440
1441static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
1442 u8 instance)
1443{
1444 struct mgmt_ev_advertising_removed ev;
1445
1446 ev.instance = instance;
1447
1448 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1449}
1450
1451static void clear_adv_instance(struct hci_dev *hdev)
1452{
1453 struct hci_request req;
1454
1455 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
1456 return;
1457
Florian Grandel5d900e42015-06-18 03:16:35 +02001458 if (hdev->adv_instance_timeout)
1459 cancel_delayed_work(&hdev->adv_instance_expire);
Arman Uguray912098a2015-03-23 15:57:15 -07001460
1461 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
1462 advertising_removed(NULL, hdev, 1);
1463 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
1464
1465 if (!hdev_is_powered(hdev) ||
1466 hci_dev_test_flag(hdev, HCI_ADVERTISING))
1467 return;
1468
1469 hci_req_init(&req, hdev);
1470 disable_advertising(&req);
1471 hci_req_run(&req, NULL);
1472}
1473
Johan Hedberg8b064a32014-02-24 14:52:22 +02001474static int clean_up_hci_state(struct hci_dev *hdev)
1475{
1476 struct hci_request req;
1477 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001478 bool discov_stopped;
1479 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001480
1481 hci_req_init(&req, hdev);
1482
1483 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1484 test_bit(HCI_PSCAN, &hdev->flags)) {
1485 u8 scan = 0x00;
1486 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1487 }
1488
Florian Grandel5d900e42015-06-18 03:16:35 +02001489 if (hdev->adv_instance_timeout)
Arman Uguray912098a2015-03-23 15:57:15 -07001490 clear_adv_instance(hdev);
1491
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001492 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001493 disable_advertising(&req);
1494
Johan Hedberg23a48092014-07-08 16:05:06 +03001495 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001496
1497 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1498 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001499 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001500
Johan Hedbergc9910d02014-02-27 14:35:12 +02001501 switch (conn->state) {
1502 case BT_CONNECTED:
1503 case BT_CONFIG:
1504 dc.handle = cpu_to_le16(conn->handle);
1505 dc.reason = 0x15; /* Terminated due to Power Off */
1506 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1507 break;
1508 case BT_CONNECT:
1509 if (conn->type == LE_LINK)
1510 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1511 0, NULL);
1512 else if (conn->type == ACL_LINK)
1513 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1514 6, &conn->dst);
1515 break;
1516 case BT_CONNECT2:
1517 bacpy(&rej.bdaddr, &conn->dst);
1518 rej.reason = 0x15; /* Terminated due to Power Off */
1519 if (conn->type == ACL_LINK)
1520 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1521 sizeof(rej), &rej);
1522 else if (conn->type == SCO_LINK)
1523 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1524 sizeof(rej), &rej);
1525 break;
1526 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001527 }
1528
Johan Hedberg23a48092014-07-08 16:05:06 +03001529 err = hci_req_run(&req, clean_up_hci_complete);
1530 if (!err && discov_stopped)
1531 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1532
1533 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001534}
1535
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001536static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001537 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001538{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001539 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001540 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001541 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001542
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001544
Johan Hedberga7e80f22013-01-09 16:05:19 +02001545 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001546 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1547 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001548
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001549 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001550
Johan Hedberg333ae952015-03-17 13:48:47 +02001551 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001552 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1553 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001554 goto failed;
1555 }
1556
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001557 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001558 cancel_delayed_work(&hdev->power_off);
1559
1560 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001561 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1562 data, len);
1563 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001564 goto failed;
1565 }
1566 }
1567
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001568 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001569 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001570 goto failed;
1571 }
1572
Johan Hedberg03811012010-12-08 00:21:06 +02001573 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1574 if (!cmd) {
1575 err = -ENOMEM;
1576 goto failed;
1577 }
1578
Johan Hedberg8b064a32014-02-24 14:52:22 +02001579 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001580 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001581 err = 0;
1582 } else {
1583 /* Disconnect connections, stop scans, etc */
1584 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001585 if (!err)
1586 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1587 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001588
Johan Hedberg8b064a32014-02-24 14:52:22 +02001589 /* ENODATA means there were no HCI commands queued */
1590 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001591 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001592 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1593 err = 0;
1594 }
1595 }
Johan Hedberg03811012010-12-08 00:21:06 +02001596
1597failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001598 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001599 return err;
1600}
1601
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001602static int new_settings(struct hci_dev *hdev, struct sock *skip)
1603{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001604 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001605
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001606 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1607 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001608}
1609
Johan Hedberg91a668b2014-07-09 13:28:26 +03001610int mgmt_new_settings(struct hci_dev *hdev)
1611{
1612 return new_settings(hdev, NULL);
1613}
1614
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001615struct cmd_lookup {
1616 struct sock *sk;
1617 struct hci_dev *hdev;
1618 u8 mgmt_status;
1619};
1620
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001621static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001622{
1623 struct cmd_lookup *match = data;
1624
1625 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1626
1627 list_del(&cmd->list);
1628
1629 if (match->sk == NULL) {
1630 match->sk = cmd->sk;
1631 sock_hold(match->sk);
1632 }
1633
1634 mgmt_pending_free(cmd);
1635}
1636
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001637static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001638{
1639 u8 *status = data;
1640
Johan Hedberga69e8372015-03-06 21:08:53 +02001641 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001642 mgmt_pending_remove(cmd);
1643}
1644
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001645static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001646{
1647 if (cmd->cmd_complete) {
1648 u8 *status = data;
1649
1650 cmd->cmd_complete(cmd, *status);
1651 mgmt_pending_remove(cmd);
1652
1653 return;
1654 }
1655
1656 cmd_status_rsp(cmd, data);
1657}
1658
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001659static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001660{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001661 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1662 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001663}
1664
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001665static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001666{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001667 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1668 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001669}
1670
Johan Hedberge6fe7982013-10-02 15:45:22 +03001671static u8 mgmt_bredr_support(struct hci_dev *hdev)
1672{
1673 if (!lmp_bredr_capable(hdev))
1674 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001675 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001676 return MGMT_STATUS_REJECTED;
1677 else
1678 return MGMT_STATUS_SUCCESS;
1679}
1680
1681static u8 mgmt_le_support(struct hci_dev *hdev)
1682{
1683 if (!lmp_le_capable(hdev))
1684 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001685 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001686 return MGMT_STATUS_REJECTED;
1687 else
1688 return MGMT_STATUS_SUCCESS;
1689}
1690
Marcel Holtmann1904a852015-01-11 13:50:44 -08001691static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1692 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001693{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001694 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001695 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001696 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001697 bool changed;
1698
1699 BT_DBG("status 0x%02x", status);
1700
1701 hci_dev_lock(hdev);
1702
Johan Hedberg333ae952015-03-17 13:48:47 +02001703 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001704 if (!cmd)
1705 goto unlock;
1706
1707 if (status) {
1708 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001709 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001710 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001711 goto remove_cmd;
1712 }
1713
1714 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001715 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001716 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001717
1718 if (hdev->discov_timeout > 0) {
1719 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1720 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1721 to);
1722 }
1723 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001724 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001725 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001726
1727 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1728
1729 if (changed)
1730 new_settings(hdev, cmd->sk);
1731
Marcel Holtmann970ba522013-10-15 06:33:57 -07001732 /* When the discoverable mode gets changed, make sure
1733 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001734 * bit correctly set. Also update page scan based on whitelist
1735 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001736 */
1737 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001738 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001739 update_class(&req);
1740 hci_req_run(&req, NULL);
1741
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001742remove_cmd:
1743 mgmt_pending_remove(cmd);
1744
1745unlock:
1746 hci_dev_unlock(hdev);
1747}
1748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001749static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001750 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001751{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001752 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001753 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001754 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001755 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001756 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001757 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001759 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001760
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001761 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1762 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001763 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1764 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001765
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001766 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001767 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1768 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001769
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001770 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001771
1772 /* Disabling discoverable requires that no timeout is set,
1773 * and enabling limited discoverable requires a timeout.
1774 */
1775 if ((cp->val == 0x00 && timeout > 0) ||
1776 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001777 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1778 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001779
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001780 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001781
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001782 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001783 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1784 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001785 goto failed;
1786 }
1787
Johan Hedberg333ae952015-03-17 13:48:47 +02001788 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1789 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001790 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1791 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001792 goto failed;
1793 }
1794
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001795 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001796 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1797 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001798 goto failed;
1799 }
1800
1801 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001802 bool changed = false;
1803
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001804 /* Setting limited discoverable when powered off is
1805 * not a valid operation since it requires a timeout
1806 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1807 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001808 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001809 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001810 changed = true;
1811 }
1812
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001813 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001814 if (err < 0)
1815 goto failed;
1816
1817 if (changed)
1818 err = new_settings(hdev, sk);
1819
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001820 goto failed;
1821 }
1822
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001823 /* If the current mode is the same, then just update the timeout
1824 * value with the new value. And if only the timeout gets updated,
1825 * then no need for any HCI transactions.
1826 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001827 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1828 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1829 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001830 cancel_delayed_work(&hdev->discov_off);
1831 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001832
Marcel Holtmann36261542013-10-15 08:28:51 -07001833 if (cp->val && hdev->discov_timeout > 0) {
1834 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001835 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001836 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001837 }
1838
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001839 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001840 goto failed;
1841 }
1842
1843 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1844 if (!cmd) {
1845 err = -ENOMEM;
1846 goto failed;
1847 }
1848
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001849 /* Cancel any potential discoverable timeout that might be
1850 * still active and store new timeout value. The arming of
1851 * the timeout happens in the complete handler.
1852 */
1853 cancel_delayed_work(&hdev->discov_off);
1854 hdev->discov_timeout = timeout;
1855
Johan Hedbergb456f872013-10-19 23:38:22 +03001856 /* Limited discoverable mode */
1857 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001858 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001859 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001860 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001861
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001862 hci_req_init(&req, hdev);
1863
Johan Hedberg9a43e252013-10-20 19:00:07 +03001864 /* The procedure for LE-only controllers is much simpler - just
1865 * update the advertising data.
1866 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001867 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001868 goto update_ad;
1869
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001870 scan = SCAN_PAGE;
1871
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001872 if (cp->val) {
1873 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001874
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001875 if (cp->val == 0x02) {
1876 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001877 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001878 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1879 hci_cp.iac_lap[1] = 0x8b;
1880 hci_cp.iac_lap[2] = 0x9e;
1881 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1882 hci_cp.iac_lap[4] = 0x8b;
1883 hci_cp.iac_lap[5] = 0x9e;
1884 } else {
1885 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001886 hci_cp.num_iac = 1;
1887 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1888 hci_cp.iac_lap[1] = 0x8b;
1889 hci_cp.iac_lap[2] = 0x9e;
1890 }
1891
1892 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1893 (hci_cp.num_iac * 3) + 1, &hci_cp);
1894
1895 scan |= SCAN_INQUIRY;
1896 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001897 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001898 }
1899
1900 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001901
Johan Hedberg9a43e252013-10-20 19:00:07 +03001902update_ad:
1903 update_adv_data(&req);
1904
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001905 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001906 if (err < 0)
1907 mgmt_pending_remove(cmd);
1908
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001909failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001910 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001911 return err;
1912}
1913
Johan Hedberg406d7802013-03-15 17:07:09 -05001914static void write_fast_connectable(struct hci_request *req, bool enable)
1915{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001916 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001917 struct hci_cp_write_page_scan_activity acp;
1918 u8 type;
1919
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001920 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001921 return;
1922
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001923 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1924 return;
1925
Johan Hedberg406d7802013-03-15 17:07:09 -05001926 if (enable) {
1927 type = PAGE_SCAN_TYPE_INTERLACED;
1928
1929 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001930 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001931 } else {
1932 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1933
1934 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001935 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001936 }
1937
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001938 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001939
Johan Hedbergbd98b992013-03-15 17:07:13 -05001940 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1941 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1942 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1943 sizeof(acp), &acp);
1944
1945 if (hdev->page_scan_type != type)
1946 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001947}
1948
Marcel Holtmann1904a852015-01-11 13:50:44 -08001949static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1950 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001951{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001952 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001953 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001954 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001955
1956 BT_DBG("status 0x%02x", status);
1957
1958 hci_dev_lock(hdev);
1959
Johan Hedberg333ae952015-03-17 13:48:47 +02001960 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001961 if (!cmd)
1962 goto unlock;
1963
Johan Hedberg37438c12013-10-14 16:20:05 +03001964 if (status) {
1965 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001966 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001967 goto remove_cmd;
1968 }
1969
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001970 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001971 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001972 conn_changed = !hci_dev_test_and_set_flag(hdev,
1973 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001974 discov_changed = false;
1975 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001976 conn_changed = hci_dev_test_and_clear_flag(hdev,
1977 HCI_CONNECTABLE);
1978 discov_changed = hci_dev_test_and_clear_flag(hdev,
1979 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001980 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001981
Johan Hedberg2b76f452013-03-15 17:07:04 -05001982 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1983
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001984 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001985 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001986 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001987 if (discov_changed)
1988 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001989 hci_update_background_scan(hdev);
1990 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001991
Johan Hedberg37438c12013-10-14 16:20:05 +03001992remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001993 mgmt_pending_remove(cmd);
1994
1995unlock:
1996 hci_dev_unlock(hdev);
1997}
1998
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001999static int set_connectable_update_settings(struct hci_dev *hdev,
2000 struct sock *sk, u8 val)
2001{
2002 bool changed = false;
2003 int err;
2004
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002005 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002006 changed = true;
2007
2008 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07002009 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002010 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002011 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
2012 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002013 }
2014
2015 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
2016 if (err < 0)
2017 return err;
2018
Johan Hedberg562064e2014-07-08 16:35:34 +03002019 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02002020 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03002021 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002022 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03002023 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002024
2025 return 0;
2026}
2027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002028static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002029 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002030{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002031 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002032 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05002033 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002034 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002035 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002036
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002037 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002038
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002039 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
2040 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002041 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2042 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002043
Johan Hedberga7e80f22013-01-09 16:05:19 +02002044 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002045 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002047
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002048 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002049
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002050 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002051 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002052 goto failed;
2053 }
2054
Johan Hedberg333ae952015-03-17 13:48:47 +02002055 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
2056 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002057 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2058 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002059 goto failed;
2060 }
2061
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002062 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
2063 if (!cmd) {
2064 err = -ENOMEM;
2065 goto failed;
2066 }
2067
Johan Hedberg2b76f452013-03-15 17:07:04 -05002068 hci_req_init(&req, hdev);
2069
Johan Hedberg9a43e252013-10-20 19:00:07 +03002070 /* If BR/EDR is not enabled and we disable advertising as a
2071 * by-product of disabling connectable, we need to update the
2072 * advertising flags.
2073 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002074 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03002075 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002076 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
2077 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03002078 }
2079 update_adv_data(&req);
2080 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03002081 if (cp->val) {
2082 scan = SCAN_PAGE;
2083 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03002084 /* If we don't have any whitelist entries just
2085 * disable all scanning. If there are entries
2086 * and we had both page and inquiry scanning
2087 * enabled then fall back to only page scanning.
2088 * Otherwise no changes are needed.
2089 */
2090 if (list_empty(&hdev->whitelist))
2091 scan = SCAN_DISABLED;
2092 else if (test_bit(HCI_ISCAN, &hdev->flags))
2093 scan = SCAN_PAGE;
2094 else
2095 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03002096
2097 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07002098 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03002099 cancel_delayed_work(&hdev->discov_off);
2100 }
2101
2102 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2103 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05002104
Johan Hedberg3bd27242014-07-28 20:53:58 +03002105no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03002106 /* Update the advertising parameters if necessary */
Arman Uguray880897d2015-03-28 12:39:00 -07002107 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
2108 hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002109 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002110
Johan Hedberg2b76f452013-03-15 17:07:04 -05002111 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03002112 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002113 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03002114 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03002115 err = set_connectable_update_settings(hdev, sk,
2116 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03002117 goto failed;
2118 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002119
2120failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002121 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002122 return err;
2123}
2124
Johan Hedbergb2939472014-07-30 09:22:23 +03002125static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002126 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002127{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002128 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07002129 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002130 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002132 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002133
Johan Hedberga7e80f22013-01-09 16:05:19 +02002134 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002135 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
2136 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002137
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002138 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002139
2140 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07002141 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002142 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002143 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002144
Johan Hedbergb2939472014-07-30 09:22:23 +03002145 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002146 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07002147 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002148
Marcel Holtmann55594352013-10-06 16:11:57 -07002149 if (changed)
2150 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002151
Marcel Holtmann55594352013-10-06 16:11:57 -07002152unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002153 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002154 return err;
2155}
Johan Hedberg72a734e2010-12-30 00:38:22 +02002156
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
2158 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002159{
2160 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002161 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002162 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002163 int err;
2164
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002165 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002166
Johan Hedberge6fe7982013-10-02 15:45:22 +03002167 status = mgmt_bredr_support(hdev);
2168 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002169 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2170 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002171
Johan Hedberga7e80f22013-01-09 16:05:19 +02002172 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002173 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2174 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002175
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002176 hci_dev_lock(hdev);
2177
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002178 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002179 bool changed = false;
2180
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002181 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002182 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02002183 changed = true;
2184 }
2185
2186 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2187 if (err < 0)
2188 goto failed;
2189
2190 if (changed)
2191 err = new_settings(hdev, sk);
2192
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002193 goto failed;
2194 }
2195
Johan Hedberg333ae952015-03-17 13:48:47 +02002196 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002197 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2198 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002199 goto failed;
2200 }
2201
2202 val = !!cp->val;
2203
2204 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
2205 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2206 goto failed;
2207 }
2208
2209 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
2210 if (!cmd) {
2211 err = -ENOMEM;
2212 goto failed;
2213 }
2214
2215 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2216 if (err < 0) {
2217 mgmt_pending_remove(cmd);
2218 goto failed;
2219 }
2220
2221failed:
2222 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002223 return err;
2224}
2225
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002226static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002227{
2228 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002229 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002230 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002231 int err;
2232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002233 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002234
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002235 status = mgmt_bredr_support(hdev);
2236 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002237 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002238
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002239 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002240 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2241 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002242
Johan Hedberga7e80f22013-01-09 16:05:19 +02002243 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002244 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2245 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002246
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002247 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002248
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002249 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002250 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002251
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002252 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002253 changed = !hci_dev_test_and_set_flag(hdev,
2254 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002255 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002256 changed = hci_dev_test_and_clear_flag(hdev,
2257 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002258 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002259 changed = hci_dev_test_and_clear_flag(hdev,
2260 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002261 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002262 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002263 }
2264
2265 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2266 if (err < 0)
2267 goto failed;
2268
2269 if (changed)
2270 err = new_settings(hdev, sk);
2271
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002272 goto failed;
2273 }
2274
Johan Hedberg333ae952015-03-17 13:48:47 +02002275 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002276 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2277 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002278 goto failed;
2279 }
2280
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002281 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002282 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2283 goto failed;
2284 }
2285
2286 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2287 if (!cmd) {
2288 err = -ENOMEM;
2289 goto failed;
2290 }
2291
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002292 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002293 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2294 sizeof(cp->val), &cp->val);
2295
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002296 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002297 if (err < 0) {
2298 mgmt_pending_remove(cmd);
2299 goto failed;
2300 }
2301
2302failed:
2303 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002304 return err;
2305}
2306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002307static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002308{
2309 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002310 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002311 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002312 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002314 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002315
Johan Hedberge6fe7982013-10-02 15:45:22 +03002316 status = mgmt_bredr_support(hdev);
2317 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002318 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002319
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002320 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002321 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2322 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002323
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002324 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002325 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2326 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002327
Johan Hedberga7e80f22013-01-09 16:05:19 +02002328 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002329 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2330 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002331
Marcel Holtmannee392692013-10-01 22:59:23 -07002332 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002333
Johan Hedberg333ae952015-03-17 13:48:47 +02002334 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002335 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2336 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002337 goto unlock;
2338 }
2339
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002340 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002341 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002342 } else {
2343 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002344 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2345 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002346 goto unlock;
2347 }
2348
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002349 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002350 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002351
2352 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2353 if (err < 0)
2354 goto unlock;
2355
2356 if (changed)
2357 err = new_settings(hdev, sk);
2358
2359unlock:
2360 hci_dev_unlock(hdev);
2361 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002362}
2363
Marcel Holtmann1904a852015-01-11 13:50:44 -08002364static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002365{
2366 struct cmd_lookup match = { NULL, hdev };
2367
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302368 hci_dev_lock(hdev);
2369
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002370 if (status) {
2371 u8 mgmt_err = mgmt_status(status);
2372
2373 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2374 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302375 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002376 }
2377
2378 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2379
2380 new_settings(hdev, match.sk);
2381
2382 if (match.sk)
2383 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002384
2385 /* Make sure the controller has a good default for
2386 * advertising data. Restrict the update to when LE
2387 * has actually been enabled. During power on, the
2388 * update in powered_update_hci will take care of it.
2389 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002390 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002391 struct hci_request req;
2392
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002393 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002394 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002395 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002396 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002397 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002398 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302399
2400unlock:
2401 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002402}
2403
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002404static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002405{
2406 struct mgmt_mode *cp = data;
2407 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002408 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002409 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002410 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002411 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002412
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002413 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002414
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002415 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002416 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2417 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002418
Johan Hedberga7e80f22013-01-09 16:05:19 +02002419 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002420 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2421 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002422
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002423 /* Bluetooth single mode LE only controllers or dual-mode
2424 * controllers configured as LE only devices, do not allow
2425 * switching LE off. These have either LE enabled explicitly
2426 * or BR/EDR has been previously switched off.
2427 *
2428 * When trying to enable an already enabled LE, then gracefully
2429 * send a positive response. Trying to disable it however will
2430 * result into rejection.
2431 */
2432 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
2433 if (cp->val == 0x01)
2434 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2435
Johan Hedberga69e8372015-03-06 21:08:53 +02002436 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2437 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002438 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03002439
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002440 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002441
2442 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002443 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002444
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002445 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002446 bool changed = false;
2447
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002448 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002449 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002450 changed = true;
2451 }
2452
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002453 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002454 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002455 changed = true;
2456 }
2457
Johan Hedberg06199cf2012-02-22 16:37:11 +02002458 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2459 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002460 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002461
2462 if (changed)
2463 err = new_settings(hdev, sk);
2464
Johan Hedberg1de028c2012-02-29 19:55:35 -08002465 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002466 }
2467
Johan Hedberg333ae952015-03-17 13:48:47 +02002468 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2469 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002470 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2471 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002472 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002473 }
2474
2475 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2476 if (!cmd) {
2477 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002478 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002479 }
2480
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002481 hci_req_init(&req, hdev);
2482
Johan Hedberg06199cf2012-02-22 16:37:11 +02002483 memset(&hci_cp, 0, sizeof(hci_cp));
2484
2485 if (val) {
2486 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002487 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002488 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002489 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002490 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002491 }
2492
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002493 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2494 &hci_cp);
2495
2496 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302497 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002498 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002499
Johan Hedberg1de028c2012-02-29 19:55:35 -08002500unlock:
2501 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002502 return err;
2503}
2504
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002505/* This is a helper function to test for pending mgmt commands that can
2506 * cause CoD or EIR HCI commands. We can only allow one such pending
2507 * mgmt command at a time since otherwise we cannot easily track what
2508 * the current values are, will be, and based on that calculate if a new
2509 * HCI command needs to be sent and if yes with what value.
2510 */
2511static bool pending_eir_or_class(struct hci_dev *hdev)
2512{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002513 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002514
2515 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2516 switch (cmd->opcode) {
2517 case MGMT_OP_ADD_UUID:
2518 case MGMT_OP_REMOVE_UUID:
2519 case MGMT_OP_SET_DEV_CLASS:
2520 case MGMT_OP_SET_POWERED:
2521 return true;
2522 }
2523 }
2524
2525 return false;
2526}
2527
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002528static const u8 bluetooth_base_uuid[] = {
2529 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2530 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2531};
2532
2533static u8 get_uuid_size(const u8 *uuid)
2534{
2535 u32 val;
2536
2537 if (memcmp(uuid, bluetooth_base_uuid, 12))
2538 return 128;
2539
2540 val = get_unaligned_le32(&uuid[12]);
2541 if (val > 0xffff)
2542 return 32;
2543
2544 return 16;
2545}
2546
Johan Hedberg92da6092013-03-15 17:06:55 -05002547static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2548{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002549 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002550
2551 hci_dev_lock(hdev);
2552
Johan Hedberg333ae952015-03-17 13:48:47 +02002553 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002554 if (!cmd)
2555 goto unlock;
2556
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002557 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2558 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002559
2560 mgmt_pending_remove(cmd);
2561
2562unlock:
2563 hci_dev_unlock(hdev);
2564}
2565
Marcel Holtmann1904a852015-01-11 13:50:44 -08002566static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002567{
2568 BT_DBG("status 0x%02x", status);
2569
2570 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2571}
2572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002573static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002574{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002575 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002576 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002577 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002578 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002579 int err;
2580
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002581 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002582
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002583 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002584
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002585 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002586 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2587 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002588 goto failed;
2589 }
2590
Andre Guedes92c4c202012-06-07 19:05:44 -03002591 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002592 if (!uuid) {
2593 err = -ENOMEM;
2594 goto failed;
2595 }
2596
2597 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002598 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002599 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002600
Johan Hedbergde66aa62013-01-27 00:31:27 +02002601 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002602
Johan Hedberg890ea892013-03-15 17:06:52 -05002603 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002604
Johan Hedberg890ea892013-03-15 17:06:52 -05002605 update_class(&req);
2606 update_eir(&req);
2607
Johan Hedberg92da6092013-03-15 17:06:55 -05002608 err = hci_req_run(&req, add_uuid_complete);
2609 if (err < 0) {
2610 if (err != -ENODATA)
2611 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002612
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002613 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2614 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002615 goto failed;
2616 }
2617
2618 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002619 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002620 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002621 goto failed;
2622 }
2623
2624 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002625
2626failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002627 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002628 return err;
2629}
2630
Johan Hedberg24b78d02012-02-23 23:24:30 +02002631static bool enable_service_cache(struct hci_dev *hdev)
2632{
2633 if (!hdev_is_powered(hdev))
2634 return false;
2635
Marcel Holtmann238be782015-03-13 02:11:06 -07002636 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002637 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2638 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002639 return true;
2640 }
2641
2642 return false;
2643}
2644
Marcel Holtmann1904a852015-01-11 13:50:44 -08002645static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002646{
2647 BT_DBG("status 0x%02x", status);
2648
2649 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2650}
2651
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002652static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002653 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002654{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002655 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002656 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002657 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002658 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 -05002659 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002660 int err, found;
2661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002663
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002664 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002665
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002666 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002667 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2668 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002669 goto unlock;
2670 }
2671
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002672 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002673 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002674
Johan Hedberg24b78d02012-02-23 23:24:30 +02002675 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002676 err = mgmt_cmd_complete(sk, hdev->id,
2677 MGMT_OP_REMOVE_UUID,
2678 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002679 goto unlock;
2680 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002681
Johan Hedberg9246a862012-02-23 21:33:16 +02002682 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002683 }
2684
2685 found = 0;
2686
Johan Hedberg056341c2013-01-27 00:31:30 +02002687 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002688 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2689 continue;
2690
2691 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002692 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002693 found++;
2694 }
2695
2696 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002697 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2698 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002699 goto unlock;
2700 }
2701
Johan Hedberg9246a862012-02-23 21:33:16 +02002702update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002703 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002704
Johan Hedberg890ea892013-03-15 17:06:52 -05002705 update_class(&req);
2706 update_eir(&req);
2707
Johan Hedberg92da6092013-03-15 17:06:55 -05002708 err = hci_req_run(&req, remove_uuid_complete);
2709 if (err < 0) {
2710 if (err != -ENODATA)
2711 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002712
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002713 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2714 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002715 goto unlock;
2716 }
2717
2718 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002719 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002720 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002721 goto unlock;
2722 }
2723
2724 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002725
2726unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002727 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002728 return err;
2729}
2730
Marcel Holtmann1904a852015-01-11 13:50:44 -08002731static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002732{
2733 BT_DBG("status 0x%02x", status);
2734
2735 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2736}
2737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002739 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002741 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002742 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002743 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002744 int err;
2745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002746 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002747
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002748 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002749 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2750 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002752 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002753
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002754 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002755 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2756 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002757 goto unlock;
2758 }
2759
2760 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002761 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2762 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002763 goto unlock;
2764 }
2765
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002766 hdev->major_class = cp->major;
2767 hdev->minor_class = cp->minor;
2768
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002769 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002770 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2771 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002772 goto unlock;
2773 }
2774
Johan Hedberg890ea892013-03-15 17:06:52 -05002775 hci_req_init(&req, hdev);
2776
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002777 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002778 hci_dev_unlock(hdev);
2779 cancel_delayed_work_sync(&hdev->service_cache);
2780 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002781 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002782 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002783
Johan Hedberg890ea892013-03-15 17:06:52 -05002784 update_class(&req);
2785
Johan Hedberg92da6092013-03-15 17:06:55 -05002786 err = hci_req_run(&req, set_class_complete);
2787 if (err < 0) {
2788 if (err != -ENODATA)
2789 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002790
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002791 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2792 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002793 goto unlock;
2794 }
2795
2796 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002797 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002798 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002799 goto unlock;
2800 }
2801
2802 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002803
Johan Hedbergb5235a62012-02-21 14:32:24 +02002804unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002805 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002806 return err;
2807}
2808
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002809static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002810 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002811{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002812 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002813 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2814 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002815 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002816 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002817 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002818
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002819 BT_DBG("request for %s", hdev->name);
2820
2821 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002822 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2823 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002824
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002825 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002826 if (key_count > max_key_count) {
2827 BT_ERR("load_link_keys: too big key_count value %u",
2828 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002829 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2830 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002831 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002832
Johan Hedberg86742e12011-11-07 23:13:38 +02002833 expected_len = sizeof(*cp) + key_count *
2834 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002835 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002836 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002837 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002838 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2839 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002840 }
2841
Johan Hedberg4ae14302013-01-20 14:27:13 +02002842 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002843 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2844 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002845
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002846 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002847 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002848
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002849 for (i = 0; i < key_count; i++) {
2850 struct mgmt_link_key_info *key = &cp->keys[i];
2851
Marcel Holtmann8e991132014-01-10 02:07:25 -08002852 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002853 return mgmt_cmd_status(sk, hdev->id,
2854 MGMT_OP_LOAD_LINK_KEYS,
2855 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002856 }
2857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002858 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002859
2860 hci_link_keys_clear(hdev);
2861
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002862 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002863 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002864 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002865 changed = hci_dev_test_and_clear_flag(hdev,
2866 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002867
2868 if (changed)
2869 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002870
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002871 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002872 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002873
Johan Hedberg58e92932014-06-24 14:00:26 +03002874 /* Always ignore debug keys and require a new pairing if
2875 * the user wants to use them.
2876 */
2877 if (key->type == HCI_LK_DEBUG_COMBINATION)
2878 continue;
2879
Johan Hedberg7652ff62014-06-24 13:15:49 +03002880 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2881 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002882 }
2883
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002884 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002885
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002886 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002887
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002888 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002889}
2890
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002891static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002892 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002893{
2894 struct mgmt_ev_device_unpaired ev;
2895
2896 bacpy(&ev.addr.bdaddr, bdaddr);
2897 ev.addr.type = addr_type;
2898
2899 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002900 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002901}
2902
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002903static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002904 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002905{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002906 struct mgmt_cp_unpair_device *cp = data;
2907 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002908 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002909 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002910 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002911 int err;
2912
Johan Hedberga8a1d192011-11-10 15:54:38 +02002913 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002914 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2915 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002916
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002917 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002918 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2919 MGMT_STATUS_INVALID_PARAMS,
2920 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002921
Johan Hedberg118da702013-01-20 14:27:20 +02002922 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002923 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2924 MGMT_STATUS_INVALID_PARAMS,
2925 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002926
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002927 hci_dev_lock(hdev);
2928
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002929 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002930 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2931 MGMT_STATUS_NOT_POWERED, &rp,
2932 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002933 goto unlock;
2934 }
2935
Johan Hedberge0b2b272014-02-18 17:14:31 +02002936 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002937 /* If disconnection is requested, then look up the
2938 * connection. If the remote device is connected, it
2939 * will be later used to terminate the link.
2940 *
2941 * Setting it to NULL explicitly will cause no
2942 * termination of the link.
2943 */
2944 if (cp->disconnect)
2945 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2946 &cp->addr.bdaddr);
2947 else
2948 conn = NULL;
2949
Johan Hedberg124f6e32012-02-09 13:50:12 +02002950 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002951 } else {
2952 u8 addr_type;
2953
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002954 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2955 &cp->addr.bdaddr);
2956 if (conn) {
2957 /* Defer clearing up the connection parameters
2958 * until closing to give a chance of keeping
2959 * them if a repairing happens.
2960 */
2961 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2962
2963 /* If disconnection is not requested, then
2964 * clear the connection variable so that the
2965 * link is not terminated.
2966 */
2967 if (!cp->disconnect)
2968 conn = NULL;
2969 }
2970
Johan Hedberge0b2b272014-02-18 17:14:31 +02002971 if (cp->addr.type == BDADDR_LE_PUBLIC)
2972 addr_type = ADDR_LE_DEV_PUBLIC;
2973 else
2974 addr_type = ADDR_LE_DEV_RANDOM;
2975
Johan Hedberga7ec7332014-02-18 17:14:35 +02002976 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2977
Johan Hedberge0b2b272014-02-18 17:14:31 +02002978 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2979 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002980
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002981 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002982 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2983 MGMT_STATUS_NOT_PAIRED, &rp,
2984 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002985 goto unlock;
2986 }
2987
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002988 /* If the connection variable is set, then termination of the
2989 * link is requested.
2990 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002991 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002992 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2993 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002994 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002995 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002996 }
2997
Johan Hedberg124f6e32012-02-09 13:50:12 +02002998 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002999 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003000 if (!cmd) {
3001 err = -ENOMEM;
3002 goto unlock;
3003 }
3004
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02003005 cmd->cmd_complete = addr_cmd_complete;
3006
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003007 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003008 dc.reason = 0x13; /* Remote User Terminated Connection */
3009 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
3010 if (err < 0)
3011 mgmt_pending_remove(cmd);
3012
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003013unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003014 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003015 return err;
3016}
3017
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003018static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003019 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003020{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003021 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02003022 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003023 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003024 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003025 int err;
3026
3027 BT_DBG("");
3028
Johan Hedberg06a63b12013-01-20 14:27:21 +02003029 memset(&rp, 0, sizeof(rp));
3030 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3031 rp.addr.type = cp->addr.type;
3032
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003033 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003034 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3035 MGMT_STATUS_INVALID_PARAMS,
3036 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003037
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003038 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039
3040 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003041 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3042 MGMT_STATUS_NOT_POWERED, &rp,
3043 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003044 goto failed;
3045 }
3046
Johan Hedberg333ae952015-03-17 13:48:47 +02003047 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003048 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3049 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003050 goto failed;
3051 }
3052
Andre Guedes591f47f2012-04-24 21:02:49 -03003053 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003054 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
3055 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02003056 else
3057 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03003058
Vishal Agarwalf9607272012-06-13 05:32:43 +05303059 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003060 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3061 MGMT_STATUS_NOT_CONNECTED, &rp,
3062 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003063 goto failed;
3064 }
3065
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003066 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003067 if (!cmd) {
3068 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003069 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003070 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02003071
Johan Hedbergf5818c22014-12-05 13:36:02 +02003072 cmd->cmd_complete = generic_cmd_complete;
3073
Johan Hedberge3f2f922014-08-18 20:33:33 +03003074 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003075 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003076 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077
3078failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003079 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003080 return err;
3081}
3082
Andre Guedes57c14772012-04-24 21:02:50 -03003083static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003084{
3085 switch (link_type) {
3086 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02003087 switch (addr_type) {
3088 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03003089 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03003090
Johan Hedberg48264f02011-11-09 13:58:58 +02003091 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003092 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003093 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02003094 }
Andre Guedes0ed09142012-04-03 08:46:54 -03003095
Johan Hedberg4c659c32011-11-07 23:13:39 +02003096 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003097 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003098 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003099 }
3100}
3101
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003102static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
3103 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02003104{
Johan Hedberg2784eb42011-01-21 13:56:35 +02003105 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02003106 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02003107 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003108 int err;
3109 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003110
3111 BT_DBG("");
3112
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003113 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003114
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003115 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003116 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
3117 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003118 goto unlock;
3119 }
3120
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003121 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02003122 list_for_each_entry(c, &hdev->conn_hash.list, list) {
3123 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003124 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003125 }
3126
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003127 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03003128 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02003129 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02003130 err = -ENOMEM;
3131 goto unlock;
3132 }
3133
Johan Hedberg2784eb42011-01-21 13:56:35 +02003134 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003135 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02003136 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
3137 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003138 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03003139 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03003140 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003141 continue;
3142 i++;
3143 }
3144
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003145 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003146
Johan Hedberg4c659c32011-11-07 23:13:39 +02003147 /* Recalculate length in case of filtered SCO connections, etc */
3148 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02003149
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003150 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
3151 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003152
Johan Hedberga38528f2011-01-22 06:46:43 +02003153 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003154
3155unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003156 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003157 return err;
3158}
3159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003160static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003161 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003162{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003163 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003164 int err;
3165
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003166 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003167 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003168 if (!cmd)
3169 return -ENOMEM;
3170
Johan Hedbergd8457692012-02-17 14:24:57 +02003171 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003172 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003173 if (err < 0)
3174 mgmt_pending_remove(cmd);
3175
3176 return err;
3177}
3178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003179static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003181{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003182 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003183 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003184 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003185 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003186 int err;
3187
3188 BT_DBG("");
3189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003190 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003191
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003192 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003193 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3194 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003195 goto failed;
3196 }
3197
Johan Hedbergd8457692012-02-17 14:24:57 +02003198 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003199 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003200 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3201 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003202 goto failed;
3203 }
3204
3205 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02003206 struct mgmt_cp_pin_code_neg_reply ncp;
3207
3208 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003209
3210 BT_ERR("PIN code is not 16 bytes long");
3211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003212 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003213 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003214 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3215 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003216
3217 goto failed;
3218 }
3219
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03003220 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003221 if (!cmd) {
3222 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003223 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003224 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003225
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003226 cmd->cmd_complete = addr_cmd_complete;
3227
Johan Hedbergd8457692012-02-17 14:24:57 +02003228 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003229 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003230 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003231
3232 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3233 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003234 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003235
3236failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003237 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003238 return err;
3239}
3240
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003241static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3242 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003243{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003244 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003245
3246 BT_DBG("");
3247
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003248 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003249 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3250 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003252 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003253
3254 hdev->io_capability = cp->io_capability;
3255
3256 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003257 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003258
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003259 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003260
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003261 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3262 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003263}
3264
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003265static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003266{
3267 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003268 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003269
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003270 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003271 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3272 continue;
3273
Johan Hedberge9a416b2011-02-19 12:05:56 -03003274 if (cmd->user_data != conn)
3275 continue;
3276
3277 return cmd;
3278 }
3279
3280 return NULL;
3281}
3282
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003283static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003284{
3285 struct mgmt_rp_pair_device rp;
3286 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003287 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003288
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003289 bacpy(&rp.addr.bdaddr, &conn->dst);
3290 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003291
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003292 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3293 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003294
3295 /* So we don't get further callbacks for this connection */
3296 conn->connect_cfm_cb = NULL;
3297 conn->security_cfm_cb = NULL;
3298 conn->disconn_cfm_cb = NULL;
3299
David Herrmann76a68ba2013-04-06 20:28:37 +02003300 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003301
3302 /* The device is paired so there is no need to remove
3303 * its connection parameters anymore.
3304 */
3305 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003306
3307 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003308
3309 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003310}
3311
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003312void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3313{
3314 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003315 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003316
3317 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003318 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003319 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003320 mgmt_pending_remove(cmd);
3321 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003322}
3323
Johan Hedberge9a416b2011-02-19 12:05:56 -03003324static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3325{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003326 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003327
3328 BT_DBG("status %u", status);
3329
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003330 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003331 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003332 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003333 return;
3334 }
3335
3336 cmd->cmd_complete(cmd, mgmt_status(status));
3337 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003338}
3339
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003340static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303341{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003342 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303343
3344 BT_DBG("status %u", status);
3345
3346 if (!status)
3347 return;
3348
3349 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003350 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303351 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003352 return;
3353 }
3354
3355 cmd->cmd_complete(cmd, mgmt_status(status));
3356 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303357}
3358
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003359static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003360 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003361{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003362 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003363 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003364 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003365 u8 sec_level, auth_type;
3366 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003367 int err;
3368
3369 BT_DBG("");
3370
Szymon Jancf950a30e2013-01-18 12:48:07 +01003371 memset(&rp, 0, sizeof(rp));
3372 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3373 rp.addr.type = cp->addr.type;
3374
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003375 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003376 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3377 MGMT_STATUS_INVALID_PARAMS,
3378 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003379
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003380 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003381 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3382 MGMT_STATUS_INVALID_PARAMS,
3383 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003384
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003385 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003386
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003387 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003388 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3389 MGMT_STATUS_NOT_POWERED, &rp,
3390 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003391 goto unlock;
3392 }
3393
Johan Hedberg55e76b32015-03-10 22:34:40 +02003394 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3395 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3396 MGMT_STATUS_ALREADY_PAIRED, &rp,
3397 sizeof(rp));
3398 goto unlock;
3399 }
3400
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003401 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003402 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003403
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003404 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003405 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3406 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003407 } else {
3408 u8 addr_type;
3409
3410 /* Convert from L2CAP channel address type to HCI address type
3411 */
3412 if (cp->addr.type == BDADDR_LE_PUBLIC)
3413 addr_type = ADDR_LE_DEV_PUBLIC;
3414 else
3415 addr_type = ADDR_LE_DEV_RANDOM;
3416
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003417 /* When pairing a new device, it is expected to remember
3418 * this device for future connections. Adding the connection
3419 * parameter information ahead of time allows tracking
3420 * of the slave preferred values and will speed up any
3421 * further connection establishment.
3422 *
3423 * If connection parameters already exist, then they
3424 * will be kept and this function does nothing.
3425 */
3426 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3427
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003428 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003429 sec_level, HCI_LE_CONN_TIMEOUT,
3430 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003431 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003432
Ville Tervo30e76272011-02-22 16:10:53 -03003433 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003434 int status;
3435
3436 if (PTR_ERR(conn) == -EBUSY)
3437 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003438 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3439 status = MGMT_STATUS_NOT_SUPPORTED;
3440 else if (PTR_ERR(conn) == -ECONNREFUSED)
3441 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003442 else
3443 status = MGMT_STATUS_CONNECT_FAILED;
3444
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003445 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3446 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003447 goto unlock;
3448 }
3449
3450 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003451 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003452 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3453 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003454 goto unlock;
3455 }
3456
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003457 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003458 if (!cmd) {
3459 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003460 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003461 goto unlock;
3462 }
3463
Johan Hedberg04ab2742014-12-05 13:36:04 +02003464 cmd->cmd_complete = pairing_complete;
3465
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003466 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003467 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003468 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003469 conn->security_cfm_cb = pairing_complete_cb;
3470 conn->disconn_cfm_cb = pairing_complete_cb;
3471 } else {
3472 conn->connect_cfm_cb = le_pairing_complete_cb;
3473 conn->security_cfm_cb = le_pairing_complete_cb;
3474 conn->disconn_cfm_cb = le_pairing_complete_cb;
3475 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003476
Johan Hedberge9a416b2011-02-19 12:05:56 -03003477 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003478 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003479
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003480 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003481 hci_conn_security(conn, sec_level, auth_type, true)) {
3482 cmd->cmd_complete(cmd, 0);
3483 mgmt_pending_remove(cmd);
3484 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003485
3486 err = 0;
3487
3488unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003489 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003490 return err;
3491}
3492
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003493static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3494 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003495{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003496 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003497 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003498 struct hci_conn *conn;
3499 int err;
3500
3501 BT_DBG("");
3502
Johan Hedberg28424702012-02-02 04:02:29 +02003503 hci_dev_lock(hdev);
3504
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003505 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003506 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3507 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003508 goto unlock;
3509 }
3510
Johan Hedberg333ae952015-03-17 13:48:47 +02003511 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003512 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003513 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3514 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003515 goto unlock;
3516 }
3517
3518 conn = cmd->user_data;
3519
3520 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003521 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3522 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003523 goto unlock;
3524 }
3525
Johan Hedberga511b352014-12-11 21:45:45 +02003526 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3527 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003528
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003529 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3530 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003531unlock:
3532 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003533 return err;
3534}
3535
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003536static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003537 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003538 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003539{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003540 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003541 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003542 int err;
3543
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003544 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003545
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003546 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003547 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3548 MGMT_STATUS_NOT_POWERED, addr,
3549 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003550 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003551 }
3552
Johan Hedberg1707c602013-03-15 17:07:15 -05003553 if (addr->type == BDADDR_BREDR)
3554 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003555 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003556 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003557
Johan Hedberg272d90d2012-02-09 15:26:12 +02003558 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003559 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3560 MGMT_STATUS_NOT_CONNECTED, addr,
3561 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003562 goto done;
3563 }
3564
Johan Hedberg1707c602013-03-15 17:07:15 -05003565 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003566 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003567 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003568 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3569 MGMT_STATUS_SUCCESS, addr,
3570 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003571 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003572 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3573 MGMT_STATUS_FAILED, addr,
3574 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003575
Brian Gix47c15e22011-11-16 13:53:14 -08003576 goto done;
3577 }
3578
Johan Hedberg1707c602013-03-15 17:07:15 -05003579 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003580 if (!cmd) {
3581 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003582 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003583 }
3584
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003585 cmd->cmd_complete = addr_cmd_complete;
3586
Brian Gix0df4c182011-11-16 13:53:13 -08003587 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003588 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3589 struct hci_cp_user_passkey_reply cp;
3590
Johan Hedberg1707c602013-03-15 17:07:15 -05003591 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003592 cp.passkey = passkey;
3593 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3594 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003595 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3596 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003597
Johan Hedberga664b5b2011-02-19 12:06:02 -03003598 if (err < 0)
3599 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003600
Brian Gix0df4c182011-11-16 13:53:13 -08003601done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003602 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003603 return err;
3604}
3605
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303606static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3607 void *data, u16 len)
3608{
3609 struct mgmt_cp_pin_code_neg_reply *cp = data;
3610
3611 BT_DBG("");
3612
Johan Hedberg1707c602013-03-15 17:07:15 -05003613 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303614 MGMT_OP_PIN_CODE_NEG_REPLY,
3615 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3616}
3617
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003618static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3619 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003620{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003621 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003622
3623 BT_DBG("");
3624
3625 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003626 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3627 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003628
Johan Hedberg1707c602013-03-15 17:07:15 -05003629 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003630 MGMT_OP_USER_CONFIRM_REPLY,
3631 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003632}
3633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003634static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003635 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003636{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003637 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003638
3639 BT_DBG("");
3640
Johan Hedberg1707c602013-03-15 17:07:15 -05003641 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003642 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3643 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003644}
3645
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003646static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3647 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003648{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003649 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003650
3651 BT_DBG("");
3652
Johan Hedberg1707c602013-03-15 17:07:15 -05003653 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003654 MGMT_OP_USER_PASSKEY_REPLY,
3655 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003656}
3657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003658static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003659 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003660{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003661 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003662
3663 BT_DBG("");
3664
Johan Hedberg1707c602013-03-15 17:07:15 -05003665 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003666 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3667 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003668}
3669
Johan Hedberg13928972013-03-15 17:07:00 -05003670static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003671{
Johan Hedberg13928972013-03-15 17:07:00 -05003672 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003673 struct hci_cp_write_local_name cp;
3674
Johan Hedberg13928972013-03-15 17:07:00 -05003675 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003676
Johan Hedberg890ea892013-03-15 17:06:52 -05003677 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003678}
3679
Marcel Holtmann1904a852015-01-11 13:50:44 -08003680static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003681{
3682 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003683 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003684
3685 BT_DBG("status 0x%02x", status);
3686
3687 hci_dev_lock(hdev);
3688
Johan Hedberg333ae952015-03-17 13:48:47 +02003689 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003690 if (!cmd)
3691 goto unlock;
3692
3693 cp = cmd->param;
3694
3695 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003696 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3697 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003698 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003699 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3700 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003701
3702 mgmt_pending_remove(cmd);
3703
3704unlock:
3705 hci_dev_unlock(hdev);
3706}
3707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003708static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003710{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003711 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003712 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003713 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003714 int err;
3715
3716 BT_DBG("");
3717
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003718 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003719
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003720 /* If the old values are the same as the new ones just return a
3721 * direct command complete event.
3722 */
3723 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3724 !memcmp(hdev->short_name, cp->short_name,
3725 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003726 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3727 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003728 goto failed;
3729 }
3730
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003731 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003732
Johan Hedbergb5235a62012-02-21 14:32:24 +02003733 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003734 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003735
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003736 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3737 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003738 if (err < 0)
3739 goto failed;
3740
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003741 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3742 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003743
Johan Hedbergb5235a62012-02-21 14:32:24 +02003744 goto failed;
3745 }
3746
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003747 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003748 if (!cmd) {
3749 err = -ENOMEM;
3750 goto failed;
3751 }
3752
Johan Hedberg13928972013-03-15 17:07:00 -05003753 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3754
Johan Hedberg890ea892013-03-15 17:06:52 -05003755 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003756
3757 if (lmp_bredr_capable(hdev)) {
3758 update_name(&req);
3759 update_eir(&req);
3760 }
3761
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003762 /* The name is stored in the scan response data and so
3763 * no need to udpate the advertising data here.
3764 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003765 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003766 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003767
Johan Hedberg13928972013-03-15 17:07:00 -05003768 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003769 if (err < 0)
3770 mgmt_pending_remove(cmd);
3771
3772failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003773 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003774 return err;
3775}
3776
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003777static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3778 u16 opcode, struct sk_buff *skb)
3779{
3780 struct mgmt_rp_read_local_oob_data mgmt_rp;
3781 size_t rp_size = sizeof(mgmt_rp);
3782 struct mgmt_pending_cmd *cmd;
3783
3784 BT_DBG("%s status %u", hdev->name, status);
3785
3786 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3787 if (!cmd)
3788 return;
3789
3790 if (status || !skb) {
3791 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3792 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3793 goto remove;
3794 }
3795
3796 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3797
3798 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3799 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3800
3801 if (skb->len < sizeof(*rp)) {
3802 mgmt_cmd_status(cmd->sk, hdev->id,
3803 MGMT_OP_READ_LOCAL_OOB_DATA,
3804 MGMT_STATUS_FAILED);
3805 goto remove;
3806 }
3807
3808 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3809 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3810
3811 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3812 } else {
3813 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3814
3815 if (skb->len < sizeof(*rp)) {
3816 mgmt_cmd_status(cmd->sk, hdev->id,
3817 MGMT_OP_READ_LOCAL_OOB_DATA,
3818 MGMT_STATUS_FAILED);
3819 goto remove;
3820 }
3821
3822 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3823 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3824
3825 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3826 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3827 }
3828
3829 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3830 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3831
3832remove:
3833 mgmt_pending_remove(cmd);
3834}
3835
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003836static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003837 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003838{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003839 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003840 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003841 int err;
3842
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003843 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003844
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003845 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003846
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003847 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003848 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3849 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003850 goto unlock;
3851 }
3852
Andre Guedes9a1a1992012-07-24 15:03:48 -03003853 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003854 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3855 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003856 goto unlock;
3857 }
3858
Johan Hedberg333ae952015-03-17 13:48:47 +02003859 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003860 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3861 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003862 goto unlock;
3863 }
3864
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003865 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003866 if (!cmd) {
3867 err = -ENOMEM;
3868 goto unlock;
3869 }
3870
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003871 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003872
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003873 if (bredr_sc_enabled(hdev))
3874 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3875 else
3876 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3877
3878 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003879 if (err < 0)
3880 mgmt_pending_remove(cmd);
3881
3882unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003883 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003884 return err;
3885}
3886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003887static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003888 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003889{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003890 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003891 int err;
3892
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003893 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003894
Johan Hedberg5d57e792015-01-23 10:10:38 +02003895 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003896 return mgmt_cmd_complete(sk, hdev->id,
3897 MGMT_OP_ADD_REMOTE_OOB_DATA,
3898 MGMT_STATUS_INVALID_PARAMS,
3899 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003900
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003901 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003902
Marcel Holtmannec109112014-01-10 02:07:30 -08003903 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3904 struct mgmt_cp_add_remote_oob_data *cp = data;
3905 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003906
Johan Hedbergc19a4952014-11-17 20:52:19 +02003907 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003908 err = mgmt_cmd_complete(sk, hdev->id,
3909 MGMT_OP_ADD_REMOTE_OOB_DATA,
3910 MGMT_STATUS_INVALID_PARAMS,
3911 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003912 goto unlock;
3913 }
3914
Marcel Holtmannec109112014-01-10 02:07:30 -08003915 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003916 cp->addr.type, cp->hash,
3917 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003918 if (err < 0)
3919 status = MGMT_STATUS_FAILED;
3920 else
3921 status = MGMT_STATUS_SUCCESS;
3922
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003923 err = mgmt_cmd_complete(sk, hdev->id,
3924 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3925 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003926 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3927 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003928 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003929 u8 status;
3930
Johan Hedberg86df9202014-10-26 20:52:27 +01003931 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003932 /* Enforce zero-valued 192-bit parameters as
3933 * long as legacy SMP OOB isn't implemented.
3934 */
3935 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3936 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003937 err = mgmt_cmd_complete(sk, hdev->id,
3938 MGMT_OP_ADD_REMOTE_OOB_DATA,
3939 MGMT_STATUS_INVALID_PARAMS,
3940 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003941 goto unlock;
3942 }
3943
Johan Hedberg86df9202014-10-26 20:52:27 +01003944 rand192 = NULL;
3945 hash192 = NULL;
3946 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003947 /* In case one of the P-192 values is set to zero,
3948 * then just disable OOB data for P-192.
3949 */
3950 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3951 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3952 rand192 = NULL;
3953 hash192 = NULL;
3954 } else {
3955 rand192 = cp->rand192;
3956 hash192 = cp->hash192;
3957 }
3958 }
3959
3960 /* In case one of the P-256 values is set to zero, then just
3961 * disable OOB data for P-256.
3962 */
3963 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3964 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3965 rand256 = NULL;
3966 hash256 = NULL;
3967 } else {
3968 rand256 = cp->rand256;
3969 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003970 }
3971
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003972 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003973 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003974 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003975 if (err < 0)
3976 status = MGMT_STATUS_FAILED;
3977 else
3978 status = MGMT_STATUS_SUCCESS;
3979
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003980 err = mgmt_cmd_complete(sk, hdev->id,
3981 MGMT_OP_ADD_REMOTE_OOB_DATA,
3982 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003983 } else {
3984 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003985 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3986 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003987 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003988
Johan Hedbergc19a4952014-11-17 20:52:19 +02003989unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003990 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003991 return err;
3992}
3993
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003994static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003995 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003996{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003997 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003998 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003999 int err;
4000
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004001 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01004002
Johan Hedbergc19a4952014-11-17 20:52:19 +02004003 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004004 return mgmt_cmd_complete(sk, hdev->id,
4005 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4006 MGMT_STATUS_INVALID_PARAMS,
4007 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02004008
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004009 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004010
Johan Hedbergeedbd582014-11-15 09:34:23 +02004011 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4012 hci_remote_oob_data_clear(hdev);
4013 status = MGMT_STATUS_SUCCESS;
4014 goto done;
4015 }
4016
Johan Hedberg6928a922014-10-26 20:46:09 +01004017 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01004018 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004019 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01004020 else
Szymon Janca6785be2012-12-13 15:11:21 +01004021 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02004022
Johan Hedbergeedbd582014-11-15 09:34:23 +02004023done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004024 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
4025 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01004026
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004027 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01004028 return err;
4029}
4030
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004031static bool trigger_bredr_inquiry(struct hci_request *req, u8 *status)
4032{
4033 struct hci_dev *hdev = req->hdev;
4034 struct hci_cp_inquiry cp;
4035 /* General inquiry access code (GIAC) */
4036 u8 lap[3] = { 0x33, 0x8b, 0x9e };
4037
4038 *status = mgmt_bredr_support(hdev);
4039 if (*status)
4040 return false;
4041
4042 if (hci_dev_test_flag(hdev, HCI_INQUIRY)) {
4043 *status = MGMT_STATUS_BUSY;
4044 return false;
4045 }
4046
4047 hci_inquiry_cache_flush(hdev);
4048
4049 memset(&cp, 0, sizeof(cp));
4050 memcpy(&cp.lap, lap, sizeof(cp.lap));
4051 cp.length = DISCOV_BREDR_INQUIRY_LEN;
4052
4053 hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
4054
4055 return true;
4056}
4057
4058static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004059{
Marcel Holtmann80190442014-12-04 11:36:36 +01004060 struct hci_dev *hdev = req->hdev;
4061 struct hci_cp_le_set_scan_param param_cp;
4062 struct hci_cp_le_set_scan_enable enable_cp;
Marcel Holtmann80190442014-12-04 11:36:36 +01004063 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004064 int err;
4065
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004066 *status = mgmt_le_support(hdev);
4067 if (*status)
4068 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004069
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004070 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
4071 /* Don't let discovery abort an outgoing connection attempt
4072 * that's using directed advertising.
4073 */
4074 if (hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
4075 *status = MGMT_STATUS_REJECTED;
Marcel Holtmann80190442014-12-04 11:36:36 +01004076 return false;
4077 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004078
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004079 disable_advertising(req);
4080 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004081
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004082 /* If controller is scanning, it means the background scanning is
4083 * running. Thus, we should temporarily stop it in order to set the
4084 * discovery scanning parameters.
4085 */
4086 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
4087 hci_req_add_le_scan_disable(req);
4088
4089 /* All active scans will be done with either a resolvable private
4090 * address (when privacy feature has been enabled) or non-resolvable
4091 * private address.
4092 */
4093 err = hci_update_random_address(req, true, &own_addr_type);
4094 if (err < 0) {
4095 *status = MGMT_STATUS_FAILED;
4096 return false;
4097 }
4098
4099 memset(&param_cp, 0, sizeof(param_cp));
4100 param_cp.type = LE_SCAN_ACTIVE;
4101 param_cp.interval = cpu_to_le16(interval);
4102 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
4103 param_cp.own_address_type = own_addr_type;
4104
4105 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
4106 &param_cp);
4107
4108 memset(&enable_cp, 0, sizeof(enable_cp));
4109 enable_cp.enable = LE_SCAN_ENABLE;
4110 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
4111
4112 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
4113 &enable_cp);
4114
4115 return true;
4116}
4117
4118static bool trigger_discovery(struct hci_request *req, u8 *status)
4119{
4120 struct hci_dev *hdev = req->hdev;
4121
4122 switch (hdev->discovery.type) {
4123 case DISCOV_TYPE_BREDR:
4124 if (!trigger_bredr_inquiry(req, status))
4125 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01004126 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004127
Marcel Holtmann80190442014-12-04 11:36:36 +01004128 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07004129 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
4130 &hdev->quirks)) {
4131 /* During simultaneous discovery, we double LE scan
4132 * interval. We must leave some time for the controller
4133 * to do BR/EDR inquiry.
4134 */
4135 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
4136 status))
4137 return false;
4138
4139 if (!trigger_bredr_inquiry(req, status))
4140 return false;
4141
4142 return true;
4143 }
4144
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004145 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01004146 *status = MGMT_STATUS_NOT_SUPPORTED;
4147 return false;
4148 }
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004149 /* fall through */
Marcel Holtmann80190442014-12-04 11:36:36 +01004150
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004151 case DISCOV_TYPE_LE:
4152 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT, status))
Marcel Holtmann80190442014-12-04 11:36:36 +01004153 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01004154 break;
4155
4156 default:
4157 *status = MGMT_STATUS_INVALID_PARAMS;
4158 return false;
4159 }
4160
4161 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004162}
4163
Marcel Holtmann1904a852015-01-11 13:50:44 -08004164static void start_discovery_complete(struct hci_dev *hdev, u8 status,
4165 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03004166{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004167 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004168 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004169
Andre Guedes7c307722013-04-30 15:29:28 -03004170 BT_DBG("status %d", status);
4171
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004172 hci_dev_lock(hdev);
4173
Johan Hedberg333ae952015-03-17 13:48:47 +02004174 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004175 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004176 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004177
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004178 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004179 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004180 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004181 }
4182
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004183 if (status) {
4184 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4185 goto unlock;
4186 }
4187
Andre Guedes7c307722013-04-30 15:29:28 -03004188 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03004189
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004190 /* If the scan involves LE scan, pick proper timeout to schedule
4191 * hdev->le_scan_disable that will stop it.
4192 */
Andre Guedes7c307722013-04-30 15:29:28 -03004193 switch (hdev->discovery.type) {
4194 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01004195 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03004196 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004197 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07004198 /* When running simultaneous discovery, the LE scanning time
4199 * should occupy the whole discovery time sine BR/EDR inquiry
4200 * and LE scanning are scheduled by the controller.
4201 *
4202 * For interleaving discovery in comparison, BR/EDR inquiry
4203 * and LE scanning are done sequentially with separate
4204 * timeouts.
4205 */
4206 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
4207 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
4208 else
4209 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03004210 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004211 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004212 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03004213 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004214 default:
4215 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004216 timeout = 0;
4217 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004218 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004219
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004220 if (timeout) {
4221 /* When service discovery is used and the controller has
4222 * a strict duplicate filter, it is important to remember
4223 * the start and duration of the scan. This is required
4224 * for restarting scanning during the discovery phase.
4225 */
4226 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
4227 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004228 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004229 hdev->discovery.scan_start = jiffies;
4230 hdev->discovery.scan_duration = timeout;
4231 }
4232
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004233 queue_delayed_work(hdev->workqueue,
4234 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004235 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004236
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004237unlock:
4238 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03004239}
4240
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004241static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004242 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004243{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004244 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004245 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03004246 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01004247 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004248 int err;
4249
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004250 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004252 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004253
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004254 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004255 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4256 MGMT_STATUS_NOT_POWERED,
4257 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004258 goto failed;
4259 }
4260
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004261 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004262 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004263 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4264 MGMT_STATUS_BUSY, &cp->type,
4265 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004266 goto failed;
4267 }
4268
Johan Hedberg2922a942014-12-05 13:36:06 +02004269 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004270 if (!cmd) {
4271 err = -ENOMEM;
4272 goto failed;
4273 }
4274
Johan Hedberg2922a942014-12-05 13:36:06 +02004275 cmd->cmd_complete = generic_cmd_complete;
4276
Marcel Holtmann22078802014-12-05 11:45:22 +01004277 /* Clear the discovery filter first to free any previously
4278 * allocated memory for the UUID list.
4279 */
4280 hci_discovery_filter_clear(hdev);
4281
Andre Guedes4aab14e2012-02-17 20:39:36 -03004282 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004283 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004284
Andre Guedes7c307722013-04-30 15:29:28 -03004285 hci_req_init(&req, hdev);
4286
Marcel Holtmann80190442014-12-04 11:36:36 +01004287 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004288 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4289 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004290 mgmt_pending_remove(cmd);
4291 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004292 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004293
Andre Guedes7c307722013-04-30 15:29:28 -03004294 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004295 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004296 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004297 goto failed;
4298 }
4299
4300 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004301
4302failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004303 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004304 return err;
4305}
4306
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004307static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4308 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004309{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004310 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4311 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004312}
4313
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004314static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4315 void *data, u16 len)
4316{
4317 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004318 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004319 struct hci_request req;
4320 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4321 u16 uuid_count, expected_len;
4322 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004323 int err;
4324
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004325 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004326
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004327 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004328
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004329 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004330 err = mgmt_cmd_complete(sk, hdev->id,
4331 MGMT_OP_START_SERVICE_DISCOVERY,
4332 MGMT_STATUS_NOT_POWERED,
4333 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004334 goto failed;
4335 }
4336
4337 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004338 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004339 err = mgmt_cmd_complete(sk, hdev->id,
4340 MGMT_OP_START_SERVICE_DISCOVERY,
4341 MGMT_STATUS_BUSY, &cp->type,
4342 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004343 goto failed;
4344 }
4345
4346 uuid_count = __le16_to_cpu(cp->uuid_count);
4347 if (uuid_count > max_uuid_count) {
4348 BT_ERR("service_discovery: too big uuid_count value %u",
4349 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004350 err = mgmt_cmd_complete(sk, hdev->id,
4351 MGMT_OP_START_SERVICE_DISCOVERY,
4352 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4353 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004354 goto failed;
4355 }
4356
4357 expected_len = sizeof(*cp) + uuid_count * 16;
4358 if (expected_len != len) {
4359 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4360 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004361 err = mgmt_cmd_complete(sk, hdev->id,
4362 MGMT_OP_START_SERVICE_DISCOVERY,
4363 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4364 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004365 goto failed;
4366 }
4367
4368 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004369 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004370 if (!cmd) {
4371 err = -ENOMEM;
4372 goto failed;
4373 }
4374
Johan Hedberg2922a942014-12-05 13:36:06 +02004375 cmd->cmd_complete = service_discovery_cmd_complete;
4376
Marcel Holtmann22078802014-12-05 11:45:22 +01004377 /* Clear the discovery filter first to free any previously
4378 * allocated memory for the UUID list.
4379 */
4380 hci_discovery_filter_clear(hdev);
4381
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004382 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004383 hdev->discovery.type = cp->type;
4384 hdev->discovery.rssi = cp->rssi;
4385 hdev->discovery.uuid_count = uuid_count;
4386
4387 if (uuid_count > 0) {
4388 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4389 GFP_KERNEL);
4390 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004391 err = mgmt_cmd_complete(sk, hdev->id,
4392 MGMT_OP_START_SERVICE_DISCOVERY,
4393 MGMT_STATUS_FAILED,
4394 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004395 mgmt_pending_remove(cmd);
4396 goto failed;
4397 }
4398 }
4399
4400 hci_req_init(&req, hdev);
4401
4402 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004403 err = mgmt_cmd_complete(sk, hdev->id,
4404 MGMT_OP_START_SERVICE_DISCOVERY,
4405 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004406 mgmt_pending_remove(cmd);
4407 goto failed;
4408 }
4409
4410 err = hci_req_run(&req, start_discovery_complete);
4411 if (err < 0) {
4412 mgmt_pending_remove(cmd);
4413 goto failed;
4414 }
4415
4416 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4417
4418failed:
4419 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004420 return err;
4421}
4422
Marcel Holtmann1904a852015-01-11 13:50:44 -08004423static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004424{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004425 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004426
Andre Guedes0e05bba2013-04-30 15:29:33 -03004427 BT_DBG("status %d", status);
4428
4429 hci_dev_lock(hdev);
4430
Johan Hedberg333ae952015-03-17 13:48:47 +02004431 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004432 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004433 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004434 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004435 }
4436
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004437 if (!status)
4438 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004439
Andre Guedes0e05bba2013-04-30 15:29:33 -03004440 hci_dev_unlock(hdev);
4441}
4442
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004443static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004444 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004445{
Johan Hedbergd9306502012-02-20 23:25:18 +02004446 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004447 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004448 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004449 int err;
4450
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004451 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004452
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004453 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004454
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004455 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004456 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4457 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4458 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004459 goto unlock;
4460 }
4461
4462 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004463 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4464 MGMT_STATUS_INVALID_PARAMS,
4465 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004466 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004467 }
4468
Johan Hedberg2922a942014-12-05 13:36:06 +02004469 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004470 if (!cmd) {
4471 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004472 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004473 }
4474
Johan Hedberg2922a942014-12-05 13:36:06 +02004475 cmd->cmd_complete = generic_cmd_complete;
4476
Andre Guedes0e05bba2013-04-30 15:29:33 -03004477 hci_req_init(&req, hdev);
4478
Johan Hedberg21a60d32014-06-10 14:05:58 +03004479 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004480
Johan Hedberg21a60d32014-06-10 14:05:58 +03004481 err = hci_req_run(&req, stop_discovery_complete);
4482 if (!err) {
4483 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004484 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004485 }
4486
Johan Hedberg21a60d32014-06-10 14:05:58 +03004487 mgmt_pending_remove(cmd);
4488
4489 /* If no HCI commands were sent we're done */
4490 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004491 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4492 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004493 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4494 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004495
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004496unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004497 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004498 return err;
4499}
4500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004501static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004502 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004503{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004504 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004505 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004506 int err;
4507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004508 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004509
Johan Hedberg561aafb2012-01-04 13:31:59 +02004510 hci_dev_lock(hdev);
4511
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004512 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004513 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4514 MGMT_STATUS_FAILED, &cp->addr,
4515 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004516 goto failed;
4517 }
4518
Johan Hedberga198e7b2012-02-17 14:27:06 +02004519 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004520 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004521 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4522 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4523 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004524 goto failed;
4525 }
4526
4527 if (cp->name_known) {
4528 e->name_state = NAME_KNOWN;
4529 list_del(&e->list);
4530 } else {
4531 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004532 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004533 }
4534
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004535 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4536 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004537
4538failed:
4539 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004540 return err;
4541}
4542
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004543static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004544 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004545{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004546 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004547 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004548 int err;
4549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004550 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004551
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004552 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004553 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4554 MGMT_STATUS_INVALID_PARAMS,
4555 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004556
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004557 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004558
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004559 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4560 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004561 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004562 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004563 goto done;
4564 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004565
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004566 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4567 sk);
4568 status = MGMT_STATUS_SUCCESS;
4569
4570done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004571 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4572 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004573
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004574 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004575
4576 return err;
4577}
4578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004579static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004580 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004581{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004582 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004583 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004584 int err;
4585
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004586 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004587
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004588 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004589 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4590 MGMT_STATUS_INVALID_PARAMS,
4591 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004592
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004593 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004594
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004595 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4596 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004597 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004598 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004599 goto done;
4600 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004601
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004602 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4603 sk);
4604 status = MGMT_STATUS_SUCCESS;
4605
4606done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004607 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4608 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004609
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004610 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004611
4612 return err;
4613}
4614
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004615static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4616 u16 len)
4617{
4618 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004619 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004620 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004621 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004622
4623 BT_DBG("%s", hdev->name);
4624
Szymon Jancc72d4b82012-03-16 16:02:57 +01004625 source = __le16_to_cpu(cp->source);
4626
4627 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004628 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4629 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004630
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004631 hci_dev_lock(hdev);
4632
Szymon Jancc72d4b82012-03-16 16:02:57 +01004633 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004634 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4635 hdev->devid_product = __le16_to_cpu(cp->product);
4636 hdev->devid_version = __le16_to_cpu(cp->version);
4637
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004638 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4639 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004640
Johan Hedberg890ea892013-03-15 17:06:52 -05004641 hci_req_init(&req, hdev);
4642 update_eir(&req);
4643 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004644
4645 hci_dev_unlock(hdev);
4646
4647 return err;
4648}
4649
Arman Uguray24b4f382015-03-23 15:57:12 -07004650static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4651 u16 opcode)
4652{
4653 BT_DBG("status %d", status);
4654}
4655
Marcel Holtmann1904a852015-01-11 13:50:44 -08004656static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4657 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004658{
4659 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004660 struct hci_request req;
Johan Hedberg4375f102013-09-25 13:26:10 +03004661
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304662 hci_dev_lock(hdev);
4663
Johan Hedberg4375f102013-09-25 13:26:10 +03004664 if (status) {
4665 u8 mgmt_err = mgmt_status(status);
4666
4667 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4668 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304669 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004670 }
4671
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004672 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004673 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004674 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004675 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004676
Johan Hedberg4375f102013-09-25 13:26:10 +03004677 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4678 &match);
4679
4680 new_settings(hdev, match.sk);
4681
4682 if (match.sk)
4683 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304684
Arman Uguray24b4f382015-03-23 15:57:12 -07004685 /* If "Set Advertising" was just disabled and instance advertising was
4686 * set up earlier, then enable the advertising instance.
4687 */
4688 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
4689 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
4690 goto unlock;
4691
4692 hci_req_init(&req, hdev);
4693
4694 update_adv_data(&req);
4695 enable_advertising(&req);
4696
4697 if (hci_req_run(&req, enable_advertising_instance) < 0)
4698 BT_ERR("Failed to re-configure advertising");
4699
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304700unlock:
4701 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004702}
4703
Marcel Holtmann21b51872013-10-10 09:47:53 -07004704static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4705 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004706{
4707 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004708 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004709 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004710 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004711 int err;
4712
4713 BT_DBG("request for %s", hdev->name);
4714
Johan Hedberge6fe7982013-10-02 15:45:22 +03004715 status = mgmt_le_support(hdev);
4716 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004717 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4718 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004719
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004720 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004721 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4722 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004723
4724 hci_dev_lock(hdev);
4725
4726 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004727
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004728 /* The following conditions are ones which mean that we should
4729 * not do any HCI communication but directly send a mgmt
4730 * response to user space (after toggling the flag if
4731 * necessary).
4732 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004733 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004734 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4735 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004736 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004737 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004738 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004739 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004740
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004741 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004742 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004743 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004744 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004745 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004746 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004747 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004748 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004749 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004750 }
4751
4752 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4753 if (err < 0)
4754 goto unlock;
4755
4756 if (changed)
4757 err = new_settings(hdev, sk);
4758
4759 goto unlock;
4760 }
4761
Johan Hedberg333ae952015-03-17 13:48:47 +02004762 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4763 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004764 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4765 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004766 goto unlock;
4767 }
4768
4769 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4770 if (!cmd) {
4771 err = -ENOMEM;
4772 goto unlock;
4773 }
4774
4775 hci_req_init(&req, hdev);
4776
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004777 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004778 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004779 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004780 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004781
Arman Uguray24b4f382015-03-23 15:57:12 -07004782 if (val) {
4783 /* Switch to instance "0" for the Set Advertising setting. */
Florian Grandelefae0022015-06-18 03:16:37 +02004784 update_inst_adv_data(&req, 0x00);
4785 update_inst_scan_rsp_data(&req, 0x00);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004786 enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004787 } else {
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004788 disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004789 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004790
4791 err = hci_req_run(&req, set_advertising_complete);
4792 if (err < 0)
4793 mgmt_pending_remove(cmd);
4794
4795unlock:
4796 hci_dev_unlock(hdev);
4797 return err;
4798}
4799
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004800static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4801 void *data, u16 len)
4802{
4803 struct mgmt_cp_set_static_address *cp = data;
4804 int err;
4805
4806 BT_DBG("%s", hdev->name);
4807
Marcel Holtmann62af4442013-10-02 22:10:32 -07004808 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004809 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4810 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004811
4812 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004813 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4814 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004815
4816 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4817 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004818 return mgmt_cmd_status(sk, hdev->id,
4819 MGMT_OP_SET_STATIC_ADDRESS,
4820 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004821
4822 /* Two most significant bits shall be set */
4823 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004824 return mgmt_cmd_status(sk, hdev->id,
4825 MGMT_OP_SET_STATIC_ADDRESS,
4826 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004827 }
4828
4829 hci_dev_lock(hdev);
4830
4831 bacpy(&hdev->static_addr, &cp->bdaddr);
4832
Marcel Holtmann93690c22015-03-06 10:11:21 -08004833 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4834 if (err < 0)
4835 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004836
Marcel Holtmann93690c22015-03-06 10:11:21 -08004837 err = new_settings(hdev, sk);
4838
4839unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004840 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004841 return err;
4842}
4843
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004844static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4845 void *data, u16 len)
4846{
4847 struct mgmt_cp_set_scan_params *cp = data;
4848 __u16 interval, window;
4849 int err;
4850
4851 BT_DBG("%s", hdev->name);
4852
4853 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004854 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4855 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004856
4857 interval = __le16_to_cpu(cp->interval);
4858
4859 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004860 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4861 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004862
4863 window = __le16_to_cpu(cp->window);
4864
4865 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004866 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4867 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004868
Marcel Holtmann899e1072013-10-14 09:55:32 -07004869 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004870 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4871 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004872
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004873 hci_dev_lock(hdev);
4874
4875 hdev->le_scan_interval = interval;
4876 hdev->le_scan_window = window;
4877
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004878 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4879 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004880
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004881 /* If background scan is running, restart it so new parameters are
4882 * loaded.
4883 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004884 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004885 hdev->discovery.state == DISCOVERY_STOPPED) {
4886 struct hci_request req;
4887
4888 hci_req_init(&req, hdev);
4889
4890 hci_req_add_le_scan_disable(&req);
4891 hci_req_add_le_passive_scan(&req);
4892
4893 hci_req_run(&req, NULL);
4894 }
4895
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004896 hci_dev_unlock(hdev);
4897
4898 return err;
4899}
4900
Marcel Holtmann1904a852015-01-11 13:50:44 -08004901static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4902 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004903{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004904 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004905
4906 BT_DBG("status 0x%02x", status);
4907
4908 hci_dev_lock(hdev);
4909
Johan Hedberg333ae952015-03-17 13:48:47 +02004910 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004911 if (!cmd)
4912 goto unlock;
4913
4914 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004915 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4916 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004917 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004918 struct mgmt_mode *cp = cmd->param;
4919
4920 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004921 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004922 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004923 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004924
Johan Hedberg33e38b32013-03-15 17:07:05 -05004925 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4926 new_settings(hdev, cmd->sk);
4927 }
4928
4929 mgmt_pending_remove(cmd);
4930
4931unlock:
4932 hci_dev_unlock(hdev);
4933}
4934
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004935static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004936 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004937{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004938 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004939 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004940 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004941 int err;
4942
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004943 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004944
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004945 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004946 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004947 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4948 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004949
Johan Hedberga7e80f22013-01-09 16:05:19 +02004950 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004951 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4952 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004953
Antti Julkuf6422ec2011-06-22 13:11:56 +03004954 hci_dev_lock(hdev);
4955
Johan Hedberg333ae952015-03-17 13:48:47 +02004956 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004957 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4958 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004959 goto unlock;
4960 }
4961
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004962 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004963 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4964 hdev);
4965 goto unlock;
4966 }
4967
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004968 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004969 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004970 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4971 hdev);
4972 new_settings(hdev, sk);
4973 goto unlock;
4974 }
4975
Johan Hedberg33e38b32013-03-15 17:07:05 -05004976 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4977 data, len);
4978 if (!cmd) {
4979 err = -ENOMEM;
4980 goto unlock;
4981 }
4982
4983 hci_req_init(&req, hdev);
4984
Johan Hedberg406d7802013-03-15 17:07:09 -05004985 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004986
4987 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004988 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004989 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4990 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004991 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004992 }
4993
Johan Hedberg33e38b32013-03-15 17:07:05 -05004994unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004995 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004996
Antti Julkuf6422ec2011-06-22 13:11:56 +03004997 return err;
4998}
4999
Marcel Holtmann1904a852015-01-11 13:50:44 -08005000static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03005001{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005002 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005003
5004 BT_DBG("status 0x%02x", status);
5005
5006 hci_dev_lock(hdev);
5007
Johan Hedberg333ae952015-03-17 13:48:47 +02005008 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005009 if (!cmd)
5010 goto unlock;
5011
5012 if (status) {
5013 u8 mgmt_err = mgmt_status(status);
5014
5015 /* We need to restore the flag if related HCI commands
5016 * failed.
5017 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005018 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005019
Johan Hedberga69e8372015-03-06 21:08:53 +02005020 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005021 } else {
5022 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
5023 new_settings(hdev, cmd->sk);
5024 }
5025
5026 mgmt_pending_remove(cmd);
5027
5028unlock:
5029 hci_dev_unlock(hdev);
5030}
5031
5032static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
5033{
5034 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005035 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03005036 struct hci_request req;
5037 int err;
5038
5039 BT_DBG("request for %s", hdev->name);
5040
5041 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005042 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5043 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005044
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005045 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005046 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5047 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005048
5049 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005050 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5051 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005052
5053 hci_dev_lock(hdev);
5054
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005055 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03005056 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5057 goto unlock;
5058 }
5059
5060 if (!hdev_is_powered(hdev)) {
5061 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005062 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
5063 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
5064 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
5065 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
5066 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005067 }
5068
Marcel Holtmannce05d602015-03-13 02:11:03 -07005069 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005070
5071 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
5072 if (err < 0)
5073 goto unlock;
5074
5075 err = new_settings(hdev, sk);
5076 goto unlock;
5077 }
5078
5079 /* Reject disabling when powered on */
5080 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005081 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5082 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005083 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005084 } else {
5085 /* When configuring a dual-mode controller to operate
5086 * with LE only and using a static address, then switching
5087 * BR/EDR back on is not allowed.
5088 *
5089 * Dual-mode controllers shall operate with the public
5090 * address as its identity address for BR/EDR and LE. So
5091 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005092 *
5093 * The same restrictions applies when secure connections
5094 * has been enabled. For BR/EDR this is a controller feature
5095 * while for LE it is a host stack feature. This means that
5096 * switching BR/EDR back on when secure connections has been
5097 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005098 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005099 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08005100 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005101 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005102 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5103 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08005104 goto unlock;
5105 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03005106 }
5107
Johan Hedberg333ae952015-03-17 13:48:47 +02005108 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005109 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
5110 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005111 goto unlock;
5112 }
5113
5114 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
5115 if (!cmd) {
5116 err = -ENOMEM;
5117 goto unlock;
5118 }
5119
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07005120 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03005121 * generates the correct flags.
5122 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005123 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005124
5125 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005126
Johan Hedberg432df052014-08-01 11:13:31 +03005127 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02005128 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005129
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005130 /* Since only the advertising data flags will change, there
5131 * is no need to update the scan response data.
5132 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07005133 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005134
Johan Hedberg0663ca22013-10-02 13:43:14 +03005135 err = hci_req_run(&req, set_bredr_complete);
5136 if (err < 0)
5137 mgmt_pending_remove(cmd);
5138
5139unlock:
5140 hci_dev_unlock(hdev);
5141 return err;
5142}
5143
Johan Hedberga1443f52015-01-23 15:42:46 +02005144static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5145{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005146 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005147 struct mgmt_mode *cp;
5148
5149 BT_DBG("%s status %u", hdev->name, status);
5150
5151 hci_dev_lock(hdev);
5152
Johan Hedberg333ae952015-03-17 13:48:47 +02005153 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005154 if (!cmd)
5155 goto unlock;
5156
5157 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005158 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5159 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005160 goto remove;
5161 }
5162
5163 cp = cmd->param;
5164
5165 switch (cp->val) {
5166 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005167 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5168 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005169 break;
5170 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005171 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005172 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005173 break;
5174 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005175 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5176 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005177 break;
5178 }
5179
5180 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5181 new_settings(hdev, cmd->sk);
5182
5183remove:
5184 mgmt_pending_remove(cmd);
5185unlock:
5186 hci_dev_unlock(hdev);
5187}
5188
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005189static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5190 void *data, u16 len)
5191{
5192 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005193 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005194 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005195 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005196 int err;
5197
5198 BT_DBG("request for %s", hdev->name);
5199
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005200 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005201 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005202 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5203 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005204
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005205 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005206 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005207 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005208 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5209 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005210
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005211 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005212 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005213 MGMT_STATUS_INVALID_PARAMS);
5214
5215 hci_dev_lock(hdev);
5216
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005217 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005218 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005219 bool changed;
5220
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005221 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005222 changed = !hci_dev_test_and_set_flag(hdev,
5223 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005224 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005225 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005226 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005227 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005228 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005229 changed = hci_dev_test_and_clear_flag(hdev,
5230 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005231 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005232 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005233
5234 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5235 if (err < 0)
5236 goto failed;
5237
5238 if (changed)
5239 err = new_settings(hdev, sk);
5240
5241 goto failed;
5242 }
5243
Johan Hedberg333ae952015-03-17 13:48:47 +02005244 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005245 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5246 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005247 goto failed;
5248 }
5249
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005250 val = !!cp->val;
5251
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005252 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5253 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005254 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5255 goto failed;
5256 }
5257
5258 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5259 if (!cmd) {
5260 err = -ENOMEM;
5261 goto failed;
5262 }
5263
Johan Hedberga1443f52015-01-23 15:42:46 +02005264 hci_req_init(&req, hdev);
5265 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5266 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005267 if (err < 0) {
5268 mgmt_pending_remove(cmd);
5269 goto failed;
5270 }
5271
5272failed:
5273 hci_dev_unlock(hdev);
5274 return err;
5275}
5276
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005277static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5278 void *data, u16 len)
5279{
5280 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005281 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005282 int err;
5283
5284 BT_DBG("request for %s", hdev->name);
5285
Johan Hedbergb97109792014-06-24 14:00:28 +03005286 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005287 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5288 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005289
5290 hci_dev_lock(hdev);
5291
5292 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005293 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005294 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005295 changed = hci_dev_test_and_clear_flag(hdev,
5296 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005297
Johan Hedbergb97109792014-06-24 14:00:28 +03005298 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005299 use_changed = !hci_dev_test_and_set_flag(hdev,
5300 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005301 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005302 use_changed = hci_dev_test_and_clear_flag(hdev,
5303 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005304
5305 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005306 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005307 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5308 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5309 sizeof(mode), &mode);
5310 }
5311
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005312 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5313 if (err < 0)
5314 goto unlock;
5315
5316 if (changed)
5317 err = new_settings(hdev, sk);
5318
5319unlock:
5320 hci_dev_unlock(hdev);
5321 return err;
5322}
5323
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005324static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5325 u16 len)
5326{
5327 struct mgmt_cp_set_privacy *cp = cp_data;
5328 bool changed;
5329 int err;
5330
5331 BT_DBG("request for %s", hdev->name);
5332
5333 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005334 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5335 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005336
5337 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005338 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5339 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005340
5341 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005342 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5343 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005344
5345 hci_dev_lock(hdev);
5346
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005347 /* If user space supports this command it is also expected to
5348 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5349 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005350 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005351
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005352 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005353 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005354 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005355 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005356 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005357 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005358 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005359 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005360 }
5361
5362 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5363 if (err < 0)
5364 goto unlock;
5365
5366 if (changed)
5367 err = new_settings(hdev, sk);
5368
5369unlock:
5370 hci_dev_unlock(hdev);
5371 return err;
5372}
5373
Johan Hedberg41edf162014-02-18 10:19:35 +02005374static bool irk_is_valid(struct mgmt_irk_info *irk)
5375{
5376 switch (irk->addr.type) {
5377 case BDADDR_LE_PUBLIC:
5378 return true;
5379
5380 case BDADDR_LE_RANDOM:
5381 /* Two most significant bits shall be set */
5382 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5383 return false;
5384 return true;
5385 }
5386
5387 return false;
5388}
5389
5390static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5391 u16 len)
5392{
5393 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005394 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5395 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005396 u16 irk_count, expected_len;
5397 int i, err;
5398
5399 BT_DBG("request for %s", hdev->name);
5400
5401 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005402 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5403 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005404
5405 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005406 if (irk_count > max_irk_count) {
5407 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005408 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5409 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005410 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005411
5412 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5413 if (expected_len != len) {
5414 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005415 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005416 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5417 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005418 }
5419
5420 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5421
5422 for (i = 0; i < irk_count; i++) {
5423 struct mgmt_irk_info *key = &cp->irks[i];
5424
5425 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005426 return mgmt_cmd_status(sk, hdev->id,
5427 MGMT_OP_LOAD_IRKS,
5428 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005429 }
5430
5431 hci_dev_lock(hdev);
5432
5433 hci_smp_irks_clear(hdev);
5434
5435 for (i = 0; i < irk_count; i++) {
5436 struct mgmt_irk_info *irk = &cp->irks[i];
5437 u8 addr_type;
5438
5439 if (irk->addr.type == BDADDR_LE_PUBLIC)
5440 addr_type = ADDR_LE_DEV_PUBLIC;
5441 else
5442 addr_type = ADDR_LE_DEV_RANDOM;
5443
5444 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5445 BDADDR_ANY);
5446 }
5447
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005448 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005449
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005450 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005451
5452 hci_dev_unlock(hdev);
5453
5454 return err;
5455}
5456
Johan Hedberg3f706b72013-01-20 14:27:16 +02005457static bool ltk_is_valid(struct mgmt_ltk_info *key)
5458{
5459 if (key->master != 0x00 && key->master != 0x01)
5460 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005461
5462 switch (key->addr.type) {
5463 case BDADDR_LE_PUBLIC:
5464 return true;
5465
5466 case BDADDR_LE_RANDOM:
5467 /* Two most significant bits shall be set */
5468 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5469 return false;
5470 return true;
5471 }
5472
5473 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005474}
5475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005476static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005477 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005478{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005479 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005480 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5481 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005482 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005483 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005484
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005485 BT_DBG("request for %s", hdev->name);
5486
5487 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005488 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5489 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005490
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005491 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005492 if (key_count > max_key_count) {
5493 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005494 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5495 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005496 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005497
5498 expected_len = sizeof(*cp) + key_count *
5499 sizeof(struct mgmt_ltk_info);
5500 if (expected_len != len) {
5501 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005502 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005503 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5504 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005505 }
5506
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005507 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005508
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005509 for (i = 0; i < key_count; i++) {
5510 struct mgmt_ltk_info *key = &cp->keys[i];
5511
Johan Hedberg3f706b72013-01-20 14:27:16 +02005512 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005513 return mgmt_cmd_status(sk, hdev->id,
5514 MGMT_OP_LOAD_LONG_TERM_KEYS,
5515 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005516 }
5517
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005518 hci_dev_lock(hdev);
5519
5520 hci_smp_ltks_clear(hdev);
5521
5522 for (i = 0; i < key_count; i++) {
5523 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005524 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005525
5526 if (key->addr.type == BDADDR_LE_PUBLIC)
5527 addr_type = ADDR_LE_DEV_PUBLIC;
5528 else
5529 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005530
Johan Hedberg61b43352014-05-29 19:36:53 +03005531 switch (key->type) {
5532 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005533 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005534 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005535 break;
5536 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005537 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005538 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005539 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005540 case MGMT_LTK_P256_UNAUTH:
5541 authenticated = 0x00;
5542 type = SMP_LTK_P256;
5543 break;
5544 case MGMT_LTK_P256_AUTH:
5545 authenticated = 0x01;
5546 type = SMP_LTK_P256;
5547 break;
5548 case MGMT_LTK_P256_DEBUG:
5549 authenticated = 0x00;
5550 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005551 default:
5552 continue;
5553 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005554
Johan Hedberg35d70272014-02-19 14:57:47 +02005555 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005556 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005557 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005558 }
5559
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005560 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005561 NULL, 0);
5562
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005563 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005564
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005565 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005566}
5567
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005568static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005569{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005570 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005571 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005572 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005573
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005574 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005575
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005576 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005577 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005578 rp.tx_power = conn->tx_power;
5579 rp.max_tx_power = conn->max_tx_power;
5580 } else {
5581 rp.rssi = HCI_RSSI_INVALID;
5582 rp.tx_power = HCI_TX_POWER_INVALID;
5583 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005584 }
5585
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005586 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5587 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005588
5589 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005590 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005591
5592 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005593}
5594
Marcel Holtmann1904a852015-01-11 13:50:44 -08005595static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5596 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005597{
5598 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005599 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005600 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005601 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005602 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005603
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005604 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005605
5606 hci_dev_lock(hdev);
5607
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005608 /* Commands sent in request are either Read RSSI or Read Transmit Power
5609 * Level so we check which one was last sent to retrieve connection
5610 * handle. Both commands have handle as first parameter so it's safe to
5611 * cast data on the same command struct.
5612 *
5613 * First command sent is always Read RSSI and we fail only if it fails.
5614 * In other case we simply override error to indicate success as we
5615 * already remembered if TX power value is actually valid.
5616 */
5617 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5618 if (!cp) {
5619 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005620 status = MGMT_STATUS_SUCCESS;
5621 } else {
5622 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005623 }
5624
5625 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005626 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005627 goto unlock;
5628 }
5629
5630 handle = __le16_to_cpu(cp->handle);
5631 conn = hci_conn_hash_lookup_handle(hdev, handle);
5632 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005633 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005634 goto unlock;
5635 }
5636
Johan Hedberg333ae952015-03-17 13:48:47 +02005637 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005638 if (!cmd)
5639 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005640
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005641 cmd->cmd_complete(cmd, status);
5642 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005643
5644unlock:
5645 hci_dev_unlock(hdev);
5646}
5647
5648static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5649 u16 len)
5650{
5651 struct mgmt_cp_get_conn_info *cp = data;
5652 struct mgmt_rp_get_conn_info rp;
5653 struct hci_conn *conn;
5654 unsigned long conn_info_age;
5655 int err = 0;
5656
5657 BT_DBG("%s", hdev->name);
5658
5659 memset(&rp, 0, sizeof(rp));
5660 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5661 rp.addr.type = cp->addr.type;
5662
5663 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005664 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5665 MGMT_STATUS_INVALID_PARAMS,
5666 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005667
5668 hci_dev_lock(hdev);
5669
5670 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005671 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5672 MGMT_STATUS_NOT_POWERED, &rp,
5673 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005674 goto unlock;
5675 }
5676
5677 if (cp->addr.type == BDADDR_BREDR)
5678 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5679 &cp->addr.bdaddr);
5680 else
5681 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5682
5683 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005684 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5685 MGMT_STATUS_NOT_CONNECTED, &rp,
5686 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005687 goto unlock;
5688 }
5689
Johan Hedberg333ae952015-03-17 13:48:47 +02005690 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005691 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5692 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005693 goto unlock;
5694 }
5695
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005696 /* To avoid client trying to guess when to poll again for information we
5697 * calculate conn info age as random value between min/max set in hdev.
5698 */
5699 conn_info_age = hdev->conn_info_min_age +
5700 prandom_u32_max(hdev->conn_info_max_age -
5701 hdev->conn_info_min_age);
5702
5703 /* Query controller to refresh cached values if they are too old or were
5704 * never read.
5705 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005706 if (time_after(jiffies, conn->conn_info_timestamp +
5707 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005708 !conn->conn_info_timestamp) {
5709 struct hci_request req;
5710 struct hci_cp_read_tx_power req_txp_cp;
5711 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005712 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005713
5714 hci_req_init(&req, hdev);
5715 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5716 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5717 &req_rssi_cp);
5718
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005719 /* For LE links TX power does not change thus we don't need to
5720 * query for it once value is known.
5721 */
5722 if (!bdaddr_type_is_le(cp->addr.type) ||
5723 conn->tx_power == HCI_TX_POWER_INVALID) {
5724 req_txp_cp.handle = cpu_to_le16(conn->handle);
5725 req_txp_cp.type = 0x00;
5726 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5727 sizeof(req_txp_cp), &req_txp_cp);
5728 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005729
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005730 /* Max TX power needs to be read only once per connection */
5731 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5732 req_txp_cp.handle = cpu_to_le16(conn->handle);
5733 req_txp_cp.type = 0x01;
5734 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5735 sizeof(req_txp_cp), &req_txp_cp);
5736 }
5737
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005738 err = hci_req_run(&req, conn_info_refresh_complete);
5739 if (err < 0)
5740 goto unlock;
5741
5742 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5743 data, len);
5744 if (!cmd) {
5745 err = -ENOMEM;
5746 goto unlock;
5747 }
5748
5749 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005750 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005751 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005752
5753 conn->conn_info_timestamp = jiffies;
5754 } else {
5755 /* Cache is valid, just reply with values cached in hci_conn */
5756 rp.rssi = conn->rssi;
5757 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005758 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005759
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005760 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5761 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005762 }
5763
5764unlock:
5765 hci_dev_unlock(hdev);
5766 return err;
5767}
5768
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005769static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005770{
5771 struct hci_conn *conn = cmd->user_data;
5772 struct mgmt_rp_get_clock_info rp;
5773 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005774 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005775
5776 memset(&rp, 0, sizeof(rp));
5777 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5778
5779 if (status)
5780 goto complete;
5781
5782 hdev = hci_dev_get(cmd->index);
5783 if (hdev) {
5784 rp.local_clock = cpu_to_le32(hdev->clock);
5785 hci_dev_put(hdev);
5786 }
5787
5788 if (conn) {
5789 rp.piconet_clock = cpu_to_le32(conn->clock);
5790 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5791 }
5792
5793complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005794 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5795 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005796
5797 if (conn) {
5798 hci_conn_drop(conn);
5799 hci_conn_put(conn);
5800 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005801
5802 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005803}
5804
Marcel Holtmann1904a852015-01-11 13:50:44 -08005805static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005806{
Johan Hedberg95868422014-06-28 17:54:07 +03005807 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005808 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005809 struct hci_conn *conn;
5810
5811 BT_DBG("%s status %u", hdev->name, status);
5812
5813 hci_dev_lock(hdev);
5814
5815 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5816 if (!hci_cp)
5817 goto unlock;
5818
5819 if (hci_cp->which) {
5820 u16 handle = __le16_to_cpu(hci_cp->handle);
5821 conn = hci_conn_hash_lookup_handle(hdev, handle);
5822 } else {
5823 conn = NULL;
5824 }
5825
Johan Hedberg333ae952015-03-17 13:48:47 +02005826 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005827 if (!cmd)
5828 goto unlock;
5829
Johan Hedberg69487372014-12-05 13:36:07 +02005830 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005831 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005832
5833unlock:
5834 hci_dev_unlock(hdev);
5835}
5836
5837static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5838 u16 len)
5839{
5840 struct mgmt_cp_get_clock_info *cp = data;
5841 struct mgmt_rp_get_clock_info rp;
5842 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005843 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005844 struct hci_request req;
5845 struct hci_conn *conn;
5846 int err;
5847
5848 BT_DBG("%s", hdev->name);
5849
5850 memset(&rp, 0, sizeof(rp));
5851 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5852 rp.addr.type = cp->addr.type;
5853
5854 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005855 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5856 MGMT_STATUS_INVALID_PARAMS,
5857 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005858
5859 hci_dev_lock(hdev);
5860
5861 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005862 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5863 MGMT_STATUS_NOT_POWERED, &rp,
5864 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005865 goto unlock;
5866 }
5867
5868 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5869 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5870 &cp->addr.bdaddr);
5871 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005872 err = mgmt_cmd_complete(sk, hdev->id,
5873 MGMT_OP_GET_CLOCK_INFO,
5874 MGMT_STATUS_NOT_CONNECTED,
5875 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005876 goto unlock;
5877 }
5878 } else {
5879 conn = NULL;
5880 }
5881
5882 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5883 if (!cmd) {
5884 err = -ENOMEM;
5885 goto unlock;
5886 }
5887
Johan Hedberg69487372014-12-05 13:36:07 +02005888 cmd->cmd_complete = clock_info_cmd_complete;
5889
Johan Hedberg95868422014-06-28 17:54:07 +03005890 hci_req_init(&req, hdev);
5891
5892 memset(&hci_cp, 0, sizeof(hci_cp));
5893 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5894
5895 if (conn) {
5896 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005897 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005898
5899 hci_cp.handle = cpu_to_le16(conn->handle);
5900 hci_cp.which = 0x01; /* Piconet clock */
5901 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5902 }
5903
5904 err = hci_req_run(&req, get_clock_info_complete);
5905 if (err < 0)
5906 mgmt_pending_remove(cmd);
5907
5908unlock:
5909 hci_dev_unlock(hdev);
5910 return err;
5911}
5912
Johan Hedberg5a154e62014-12-19 22:26:02 +02005913static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5914{
5915 struct hci_conn *conn;
5916
5917 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5918 if (!conn)
5919 return false;
5920
5921 if (conn->dst_type != type)
5922 return false;
5923
5924 if (conn->state != BT_CONNECTED)
5925 return false;
5926
5927 return true;
5928}
5929
5930/* This function requires the caller holds hdev->lock */
5931static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5932 u8 addr_type, u8 auto_connect)
5933{
5934 struct hci_dev *hdev = req->hdev;
5935 struct hci_conn_params *params;
5936
5937 params = hci_conn_params_add(hdev, addr, addr_type);
5938 if (!params)
5939 return -EIO;
5940
5941 if (params->auto_connect == auto_connect)
5942 return 0;
5943
5944 list_del_init(&params->action);
5945
5946 switch (auto_connect) {
5947 case HCI_AUTO_CONN_DISABLED:
5948 case HCI_AUTO_CONN_LINK_LOSS:
5949 __hci_update_background_scan(req);
5950 break;
5951 case HCI_AUTO_CONN_REPORT:
5952 list_add(&params->action, &hdev->pend_le_reports);
5953 __hci_update_background_scan(req);
5954 break;
5955 case HCI_AUTO_CONN_DIRECT:
5956 case HCI_AUTO_CONN_ALWAYS:
5957 if (!is_connected(hdev, addr, addr_type)) {
5958 list_add(&params->action, &hdev->pend_le_conns);
5959 __hci_update_background_scan(req);
5960 }
5961 break;
5962 }
5963
5964 params->auto_connect = auto_connect;
5965
5966 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5967 auto_connect);
5968
5969 return 0;
5970}
5971
Marcel Holtmann8afef092014-06-29 22:28:34 +02005972static void device_added(struct sock *sk, struct hci_dev *hdev,
5973 bdaddr_t *bdaddr, u8 type, u8 action)
5974{
5975 struct mgmt_ev_device_added ev;
5976
5977 bacpy(&ev.addr.bdaddr, bdaddr);
5978 ev.addr.type = type;
5979 ev.action = action;
5980
5981 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5982}
5983
Marcel Holtmann1904a852015-01-11 13:50:44 -08005984static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005985{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005986 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005987
5988 BT_DBG("status 0x%02x", status);
5989
5990 hci_dev_lock(hdev);
5991
Johan Hedberg333ae952015-03-17 13:48:47 +02005992 cmd = pending_find(MGMT_OP_ADD_DEVICE, hdev);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005993 if (!cmd)
5994 goto unlock;
5995
5996 cmd->cmd_complete(cmd, mgmt_status(status));
5997 mgmt_pending_remove(cmd);
5998
5999unlock:
6000 hci_dev_unlock(hdev);
6001}
6002
Marcel Holtmann2faade52014-06-29 19:44:03 +02006003static int add_device(struct sock *sk, struct hci_dev *hdev,
6004 void *data, u16 len)
6005{
6006 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006007 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02006008 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006009 u8 auto_conn, addr_type;
6010 int err;
6011
6012 BT_DBG("%s", hdev->name);
6013
Johan Hedberg66593582014-07-09 12:59:14 +03006014 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02006015 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006016 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6017 MGMT_STATUS_INVALID_PARAMS,
6018 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006019
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006020 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006021 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
6022 MGMT_STATUS_INVALID_PARAMS,
6023 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02006024
Johan Hedberg5a154e62014-12-19 22:26:02 +02006025 hci_req_init(&req, hdev);
6026
Marcel Holtmann2faade52014-06-29 19:44:03 +02006027 hci_dev_lock(hdev);
6028
Johan Hedberg5a154e62014-12-19 22:26:02 +02006029 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
6030 if (!cmd) {
6031 err = -ENOMEM;
6032 goto unlock;
6033 }
6034
6035 cmd->cmd_complete = addr_cmd_complete;
6036
Johan Hedberg66593582014-07-09 12:59:14 +03006037 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006038 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03006039 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006040 err = cmd->cmd_complete(cmd,
6041 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006042 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03006043 goto unlock;
6044 }
6045
6046 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
6047 cp->addr.type);
6048 if (err)
6049 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03006050
Johan Hedberg5a154e62014-12-19 22:26:02 +02006051 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006052
Johan Hedberg66593582014-07-09 12:59:14 +03006053 goto added;
6054 }
6055
Marcel Holtmann2faade52014-06-29 19:44:03 +02006056 if (cp->addr.type == BDADDR_LE_PUBLIC)
6057 addr_type = ADDR_LE_DEV_PUBLIC;
6058 else
6059 addr_type = ADDR_LE_DEV_RANDOM;
6060
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006061 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02006062 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006063 else if (cp->action == 0x01)
6064 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006065 else
Johan Hedberga3451d22014-07-02 17:37:27 +03006066 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006067
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02006068 /* If the connection parameters don't exist for this device,
6069 * they will be created and configured with defaults.
6070 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02006071 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02006072 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006073 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006074 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006075 goto unlock;
6076 }
6077
Johan Hedberg66593582014-07-09 12:59:14 +03006078added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02006079 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
6080
Johan Hedberg5a154e62014-12-19 22:26:02 +02006081 err = hci_req_run(&req, add_device_complete);
6082 if (err < 0) {
6083 /* ENODATA means no HCI commands were needed (e.g. if
6084 * the adapter is powered off).
6085 */
Johan Hedberg9df74652014-12-19 22:26:03 +02006086 if (err == -ENODATA)
6087 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02006088 mgmt_pending_remove(cmd);
6089 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02006090
6091unlock:
6092 hci_dev_unlock(hdev);
6093 return err;
6094}
6095
Marcel Holtmann8afef092014-06-29 22:28:34 +02006096static void device_removed(struct sock *sk, struct hci_dev *hdev,
6097 bdaddr_t *bdaddr, u8 type)
6098{
6099 struct mgmt_ev_device_removed ev;
6100
6101 bacpy(&ev.addr.bdaddr, bdaddr);
6102 ev.addr.type = type;
6103
6104 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
6105}
6106
Marcel Holtmann1904a852015-01-11 13:50:44 -08006107static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006108{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006109 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006110
6111 BT_DBG("status 0x%02x", status);
6112
6113 hci_dev_lock(hdev);
6114
Johan Hedberg333ae952015-03-17 13:48:47 +02006115 cmd = pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006116 if (!cmd)
6117 goto unlock;
6118
6119 cmd->cmd_complete(cmd, mgmt_status(status));
6120 mgmt_pending_remove(cmd);
6121
6122unlock:
6123 hci_dev_unlock(hdev);
6124}
6125
Marcel Holtmann2faade52014-06-29 19:44:03 +02006126static int remove_device(struct sock *sk, struct hci_dev *hdev,
6127 void *data, u16 len)
6128{
6129 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006130 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006131 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006132 int err;
6133
6134 BT_DBG("%s", hdev->name);
6135
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006136 hci_req_init(&req, hdev);
6137
Marcel Holtmann2faade52014-06-29 19:44:03 +02006138 hci_dev_lock(hdev);
6139
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006140 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
6141 if (!cmd) {
6142 err = -ENOMEM;
6143 goto unlock;
6144 }
6145
6146 cmd->cmd_complete = addr_cmd_complete;
6147
Marcel Holtmann2faade52014-06-29 19:44:03 +02006148 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006149 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006150 u8 addr_type;
6151
Johan Hedberg66593582014-07-09 12:59:14 +03006152 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006153 err = cmd->cmd_complete(cmd,
6154 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006155 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006156 goto unlock;
6157 }
6158
Johan Hedberg66593582014-07-09 12:59:14 +03006159 if (cp->addr.type == BDADDR_BREDR) {
6160 err = hci_bdaddr_list_del(&hdev->whitelist,
6161 &cp->addr.bdaddr,
6162 cp->addr.type);
6163 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006164 err = cmd->cmd_complete(cmd,
6165 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006166 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03006167 goto unlock;
6168 }
6169
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006170 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006171
Johan Hedberg66593582014-07-09 12:59:14 +03006172 device_removed(sk, hdev, &cp->addr.bdaddr,
6173 cp->addr.type);
6174 goto complete;
6175 }
6176
Marcel Holtmann2faade52014-06-29 19:44:03 +02006177 if (cp->addr.type == BDADDR_LE_PUBLIC)
6178 addr_type = ADDR_LE_DEV_PUBLIC;
6179 else
6180 addr_type = ADDR_LE_DEV_RANDOM;
6181
Johan Hedbergc71593d2014-07-02 17:37:28 +03006182 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6183 addr_type);
6184 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006185 err = cmd->cmd_complete(cmd,
6186 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006187 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006188 goto unlock;
6189 }
6190
6191 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006192 err = cmd->cmd_complete(cmd,
6193 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006194 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006195 goto unlock;
6196 }
6197
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006198 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006199 list_del(&params->list);
6200 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006201 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006202
6203 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006204 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006205 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006206 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006207
Marcel Holtmann2faade52014-06-29 19:44:03 +02006208 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006209 err = cmd->cmd_complete(cmd,
6210 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006211 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006212 goto unlock;
6213 }
6214
Johan Hedberg66593582014-07-09 12:59:14 +03006215 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6216 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6217 list_del(&b->list);
6218 kfree(b);
6219 }
6220
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006221 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006222
Johan Hedberg19de0822014-07-06 13:06:51 +03006223 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6224 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6225 continue;
6226 device_removed(sk, hdev, &p->addr, p->addr_type);
6227 list_del(&p->action);
6228 list_del(&p->list);
6229 kfree(p);
6230 }
6231
6232 BT_DBG("All LE connection parameters were removed");
6233
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006234 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006235 }
6236
Johan Hedberg66593582014-07-09 12:59:14 +03006237complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006238 err = hci_req_run(&req, remove_device_complete);
6239 if (err < 0) {
6240 /* ENODATA means no HCI commands were needed (e.g. if
6241 * the adapter is powered off).
6242 */
Johan Hedberg9df74652014-12-19 22:26:03 +02006243 if (err == -ENODATA)
6244 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006245 mgmt_pending_remove(cmd);
6246 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02006247
6248unlock:
6249 hci_dev_unlock(hdev);
6250 return err;
6251}
6252
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006253static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6254 u16 len)
6255{
6256 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006257 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6258 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006259 u16 param_count, expected_len;
6260 int i;
6261
6262 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006263 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6264 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006265
6266 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006267 if (param_count > max_param_count) {
6268 BT_ERR("load_conn_param: too big param_count value %u",
6269 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006270 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6271 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006272 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006273
6274 expected_len = sizeof(*cp) + param_count *
6275 sizeof(struct mgmt_conn_param);
6276 if (expected_len != len) {
6277 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
6278 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006279 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6280 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006281 }
6282
6283 BT_DBG("%s param_count %u", hdev->name, param_count);
6284
6285 hci_dev_lock(hdev);
6286
6287 hci_conn_params_clear_disabled(hdev);
6288
6289 for (i = 0; i < param_count; i++) {
6290 struct mgmt_conn_param *param = &cp->params[i];
6291 struct hci_conn_params *hci_param;
6292 u16 min, max, latency, timeout;
6293 u8 addr_type;
6294
6295 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6296 param->addr.type);
6297
6298 if (param->addr.type == BDADDR_LE_PUBLIC) {
6299 addr_type = ADDR_LE_DEV_PUBLIC;
6300 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6301 addr_type = ADDR_LE_DEV_RANDOM;
6302 } else {
6303 BT_ERR("Ignoring invalid connection parameters");
6304 continue;
6305 }
6306
6307 min = le16_to_cpu(param->min_interval);
6308 max = le16_to_cpu(param->max_interval);
6309 latency = le16_to_cpu(param->latency);
6310 timeout = le16_to_cpu(param->timeout);
6311
6312 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6313 min, max, latency, timeout);
6314
6315 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6316 BT_ERR("Ignoring invalid connection parameters");
6317 continue;
6318 }
6319
6320 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6321 addr_type);
6322 if (!hci_param) {
6323 BT_ERR("Failed to add connection parameters");
6324 continue;
6325 }
6326
6327 hci_param->conn_min_interval = min;
6328 hci_param->conn_max_interval = max;
6329 hci_param->conn_latency = latency;
6330 hci_param->supervision_timeout = timeout;
6331 }
6332
6333 hci_dev_unlock(hdev);
6334
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006335 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6336 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006337}
6338
Marcel Holtmanndbece372014-07-04 18:11:55 +02006339static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6340 void *data, u16 len)
6341{
6342 struct mgmt_cp_set_external_config *cp = data;
6343 bool changed;
6344 int err;
6345
6346 BT_DBG("%s", hdev->name);
6347
6348 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006349 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6350 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006351
6352 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006353 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6354 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006355
6356 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006357 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6358 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006359
6360 hci_dev_lock(hdev);
6361
6362 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006363 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006364 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006365 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006366
6367 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6368 if (err < 0)
6369 goto unlock;
6370
6371 if (!changed)
6372 goto unlock;
6373
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006374 err = new_options(hdev, sk);
6375
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006376 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006377 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006378
Marcel Holtmann516018a2015-03-13 02:11:04 -07006379 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006380 hci_dev_set_flag(hdev, HCI_CONFIG);
6381 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006382
6383 queue_work(hdev->req_workqueue, &hdev->power_on);
6384 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006385 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006386 mgmt_index_added(hdev);
6387 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006388 }
6389
6390unlock:
6391 hci_dev_unlock(hdev);
6392 return err;
6393}
6394
Marcel Holtmann9713c172014-07-06 12:11:15 +02006395static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6396 void *data, u16 len)
6397{
6398 struct mgmt_cp_set_public_address *cp = data;
6399 bool changed;
6400 int err;
6401
6402 BT_DBG("%s", hdev->name);
6403
6404 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006405 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6406 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006407
6408 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006409 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6410 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006411
6412 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006413 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6414 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006415
6416 hci_dev_lock(hdev);
6417
6418 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6419 bacpy(&hdev->public_addr, &cp->bdaddr);
6420
6421 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6422 if (err < 0)
6423 goto unlock;
6424
6425 if (!changed)
6426 goto unlock;
6427
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006428 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006429 err = new_options(hdev, sk);
6430
6431 if (is_configured(hdev)) {
6432 mgmt_index_removed(hdev);
6433
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006434 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006435
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006436 hci_dev_set_flag(hdev, HCI_CONFIG);
6437 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006438
6439 queue_work(hdev->req_workqueue, &hdev->power_on);
6440 }
6441
6442unlock:
6443 hci_dev_unlock(hdev);
6444 return err;
6445}
6446
Marcel Holtmannbea41602015-03-14 22:43:17 -07006447static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6448 u8 data_len)
6449{
6450 eir[eir_len++] = sizeof(type) + data_len;
6451 eir[eir_len++] = type;
6452 memcpy(&eir[eir_len], data, data_len);
6453 eir_len += data_len;
6454
6455 return eir_len;
6456}
6457
Johan Hedberg40f66c02015-04-07 21:52:22 +03006458static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
6459 u16 opcode, struct sk_buff *skb)
6460{
6461 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
6462 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
6463 u8 *h192, *r192, *h256, *r256;
6464 struct mgmt_pending_cmd *cmd;
6465 u16 eir_len;
6466 int err;
6467
6468 BT_DBG("%s status %u", hdev->name, status);
6469
6470 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
6471 if (!cmd)
6472 return;
6473
6474 mgmt_cp = cmd->param;
6475
6476 if (status) {
6477 status = mgmt_status(status);
6478 eir_len = 0;
6479
6480 h192 = NULL;
6481 r192 = NULL;
6482 h256 = NULL;
6483 r256 = NULL;
6484 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
6485 struct hci_rp_read_local_oob_data *rp;
6486
6487 if (skb->len != sizeof(*rp)) {
6488 status = MGMT_STATUS_FAILED;
6489 eir_len = 0;
6490 } else {
6491 status = MGMT_STATUS_SUCCESS;
6492 rp = (void *)skb->data;
6493
6494 eir_len = 5 + 18 + 18;
6495 h192 = rp->hash;
6496 r192 = rp->rand;
6497 h256 = NULL;
6498 r256 = NULL;
6499 }
6500 } else {
6501 struct hci_rp_read_local_oob_ext_data *rp;
6502
6503 if (skb->len != sizeof(*rp)) {
6504 status = MGMT_STATUS_FAILED;
6505 eir_len = 0;
6506 } else {
6507 status = MGMT_STATUS_SUCCESS;
6508 rp = (void *)skb->data;
6509
6510 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
6511 eir_len = 5 + 18 + 18;
6512 h192 = NULL;
6513 r192 = NULL;
6514 } else {
6515 eir_len = 5 + 18 + 18 + 18 + 18;
6516 h192 = rp->hash192;
6517 r192 = rp->rand192;
6518 }
6519
6520 h256 = rp->hash256;
6521 r256 = rp->rand256;
6522 }
6523 }
6524
6525 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
6526 if (!mgmt_rp)
6527 goto done;
6528
6529 if (status)
6530 goto send_rsp;
6531
6532 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
6533 hdev->dev_class, 3);
6534
6535 if (h192 && r192) {
6536 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6537 EIR_SSP_HASH_C192, h192, 16);
6538 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6539 EIR_SSP_RAND_R192, r192, 16);
6540 }
6541
6542 if (h256 && r256) {
6543 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6544 EIR_SSP_HASH_C256, h256, 16);
6545 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
6546 EIR_SSP_RAND_R256, r256, 16);
6547 }
6548
6549send_rsp:
6550 mgmt_rp->type = mgmt_cp->type;
6551 mgmt_rp->eir_len = cpu_to_le16(eir_len);
6552
6553 err = mgmt_cmd_complete(cmd->sk, hdev->id,
6554 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
6555 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
6556 if (err < 0 || status)
6557 goto done;
6558
6559 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
6560
6561 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6562 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
6563 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
6564done:
6565 kfree(mgmt_rp);
6566 mgmt_pending_remove(cmd);
6567}
6568
6569static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
6570 struct mgmt_cp_read_local_oob_ext_data *cp)
6571{
6572 struct mgmt_pending_cmd *cmd;
6573 struct hci_request req;
6574 int err;
6575
6576 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
6577 cp, sizeof(*cp));
6578 if (!cmd)
6579 return -ENOMEM;
6580
6581 hci_req_init(&req, hdev);
6582
6583 if (bredr_sc_enabled(hdev))
6584 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
6585 else
6586 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
6587
6588 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
6589 if (err < 0) {
6590 mgmt_pending_remove(cmd);
6591 return err;
6592 }
6593
6594 return 0;
6595}
6596
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006597static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6598 void *data, u16 data_len)
6599{
6600 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6601 struct mgmt_rp_read_local_oob_ext_data *rp;
6602 size_t rp_len;
6603 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006604 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006605 int err;
6606
6607 BT_DBG("%s", hdev->name);
6608
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006609 if (hdev_is_powered(hdev)) {
6610 switch (cp->type) {
6611 case BIT(BDADDR_BREDR):
6612 status = mgmt_bredr_support(hdev);
6613 if (status)
6614 eir_len = 0;
6615 else
6616 eir_len = 5;
6617 break;
6618 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6619 status = mgmt_le_support(hdev);
6620 if (status)
6621 eir_len = 0;
6622 else
6623 eir_len = 9 + 3 + 18 + 18 + 3;
6624 break;
6625 default:
6626 status = MGMT_STATUS_INVALID_PARAMS;
6627 eir_len = 0;
6628 break;
6629 }
6630 } else {
6631 status = MGMT_STATUS_NOT_POWERED;
6632 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006633 }
6634
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006635 rp_len = sizeof(*rp) + eir_len;
6636 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006637 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006638 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006639
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006640 if (status)
6641 goto complete;
6642
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006643 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006644
6645 eir_len = 0;
6646 switch (cp->type) {
6647 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03006648 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
6649 err = read_local_ssp_oob_req(hdev, sk, cp);
6650 hci_dev_unlock(hdev);
6651 if (!err)
6652 goto done;
6653
6654 status = MGMT_STATUS_FAILED;
6655 goto complete;
6656 } else {
6657 eir_len = eir_append_data(rp->eir, eir_len,
6658 EIR_CLASS_OF_DEV,
6659 hdev->dev_class, 3);
6660 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006661 break;
6662 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006663 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6664 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006665 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006666 status = MGMT_STATUS_FAILED;
6667 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006668 }
6669
Marcel Holtmanne2135682015-04-02 12:00:58 -07006670 /* This should return the active RPA, but since the RPA
6671 * is only programmed on demand, it is really hard to fill
6672 * this in at the moment. For now disallow retrieving
6673 * local out-of-band data when privacy is in use.
6674 *
6675 * Returning the identity address will not help here since
6676 * pairing happens before the identity resolving key is
6677 * known and thus the connection establishment happens
6678 * based on the RPA and not the identity address.
6679 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006680 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07006681 hci_dev_unlock(hdev);
6682 status = MGMT_STATUS_REJECTED;
6683 goto complete;
6684 }
6685
6686 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6687 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6688 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6689 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006690 memcpy(addr, &hdev->static_addr, 6);
6691 addr[6] = 0x01;
6692 } else {
6693 memcpy(addr, &hdev->bdaddr, 6);
6694 addr[6] = 0x00;
6695 }
6696
6697 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6698 addr, sizeof(addr));
6699
6700 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6701 role = 0x02;
6702 else
6703 role = 0x01;
6704
6705 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6706 &role, sizeof(role));
6707
Marcel Holtmann5082a592015-03-16 12:39:00 -07006708 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6709 eir_len = eir_append_data(rp->eir, eir_len,
6710 EIR_LE_SC_CONFIRM,
6711 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006712
Marcel Holtmann5082a592015-03-16 12:39:00 -07006713 eir_len = eir_append_data(rp->eir, eir_len,
6714 EIR_LE_SC_RANDOM,
6715 rand, sizeof(rand));
6716 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006717
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006718 flags = get_adv_discov_flags(hdev);
6719
6720 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6721 flags |= LE_AD_NO_BREDR;
6722
6723 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6724 &flags, sizeof(flags));
6725 break;
6726 }
6727
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006728 hci_dev_unlock(hdev);
6729
Marcel Holtmann72000df2015-03-16 16:11:21 -07006730 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6731
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006732 status = MGMT_STATUS_SUCCESS;
6733
6734complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07006735 rp->type = cp->type;
6736 rp->eir_len = cpu_to_le16(eir_len);
6737
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006738 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07006739 status, rp, sizeof(*rp) + eir_len);
6740 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07006741 goto done;
6742
6743 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6744 rp, sizeof(*rp) + eir_len,
6745 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006746
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006747done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006748 kfree(rp);
6749
6750 return err;
6751}
6752
Arman Uguray089fa8c2015-03-25 18:53:45 -07006753static u32 get_supported_adv_flags(struct hci_dev *hdev)
6754{
6755 u32 flags = 0;
6756
6757 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6758 flags |= MGMT_ADV_FLAG_DISCOV;
6759 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6760 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
6761
6762 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
6763 flags |= MGMT_ADV_FLAG_TX_POWER;
6764
6765 return flags;
6766}
6767
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006768static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6769 void *data, u16 data_len)
6770{
6771 struct mgmt_rp_read_adv_features *rp;
6772 size_t rp_len;
Florian Grandel286e0c82015-06-18 03:16:38 +02006773 int err, i;
Arman Uguray24b4f382015-03-23 15:57:12 -07006774 bool instance;
Florian Grandel286e0c82015-06-18 03:16:38 +02006775 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006776 u32 supported_flags;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006777
6778 BT_DBG("%s", hdev->name);
6779
Arman Uguray089fa8c2015-03-25 18:53:45 -07006780 if (!lmp_le_capable(hdev))
6781 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6782 MGMT_STATUS_REJECTED);
6783
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006784 hci_dev_lock(hdev);
6785
6786 rp_len = sizeof(*rp);
Arman Uguray24b4f382015-03-23 15:57:12 -07006787
Arman Uguray24b4f382015-03-23 15:57:12 -07006788 instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
6789 if (instance)
Florian Grandel286e0c82015-06-18 03:16:38 +02006790 rp_len += hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006791
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006792 rp = kmalloc(rp_len, GFP_ATOMIC);
6793 if (!rp) {
6794 hci_dev_unlock(hdev);
6795 return -ENOMEM;
6796 }
6797
Arman Uguray089fa8c2015-03-25 18:53:45 -07006798 supported_flags = get_supported_adv_flags(hdev);
6799
6800 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006801 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6802 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006803 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Arman Uguray24b4f382015-03-23 15:57:12 -07006804
Arman Uguray24b4f382015-03-23 15:57:12 -07006805 if (instance) {
Florian Grandel286e0c82015-06-18 03:16:38 +02006806 i = 0;
6807 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6808 if (i >= hdev->adv_instance_cnt)
6809 break;
6810
6811 rp->instance[i] = adv_instance->instance;
6812 i++;
6813 }
6814 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006815 } else {
6816 rp->num_instances = 0;
6817 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006818
6819 hci_dev_unlock(hdev);
6820
6821 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6822 MGMT_STATUS_SUCCESS, rp, rp_len);
6823
6824 kfree(rp);
6825
6826 return err;
6827}
6828
Arman Uguray4117ed72015-03-23 15:57:14 -07006829static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006830 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006831{
Arman Uguray4117ed72015-03-23 15:57:14 -07006832 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006833 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07006834 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07006835 bool tx_power_managed = false;
Arman Uguray67e0c0c2015-03-25 18:53:43 -07006836 u32 flags_params = MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
6837 MGMT_ADV_FLAG_MANAGED_FLAGS;
Arman Uguray24b4f382015-03-23 15:57:12 -07006838
Arman Uguray807ec772015-03-25 18:53:42 -07006839 if (is_adv_data && (adv_flags & flags_params)) {
Arman Ugurayb44133f2015-03-25 18:53:41 -07006840 flags_managed = true;
6841 max_len -= 3;
6842 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006843
Arman Uguray5507e352015-03-25 18:53:44 -07006844 if (is_adv_data && (adv_flags & MGMT_ADV_FLAG_TX_POWER)) {
6845 tx_power_managed = true;
6846 max_len -= 3;
6847 }
6848
Arman Uguray4117ed72015-03-23 15:57:14 -07006849 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006850 return false;
6851
Arman Uguray4117ed72015-03-23 15:57:14 -07006852 /* Make sure that the data is correctly formatted. */
6853 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6854 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006855
Arman Ugurayb44133f2015-03-25 18:53:41 -07006856 if (flags_managed && data[i + 1] == EIR_FLAGS)
6857 return false;
6858
Arman Uguray5507e352015-03-25 18:53:44 -07006859 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
6860 return false;
6861
Arman Uguray24b4f382015-03-23 15:57:12 -07006862 /* If the current field length would exceed the total data
6863 * length, then it's invalid.
6864 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006865 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006866 return false;
6867 }
6868
6869 return true;
6870}
6871
Arman Uguray24b4f382015-03-23 15:57:12 -07006872static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6873 u16 opcode)
6874{
6875 struct mgmt_pending_cmd *cmd;
6876 struct mgmt_rp_add_advertising rp;
6877
6878 BT_DBG("status %d", status);
6879
6880 hci_dev_lock(hdev);
6881
6882 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6883
6884 if (status) {
6885 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
6886 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
6887 advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
6888 }
6889
6890 if (!cmd)
6891 goto unlock;
6892
6893 rp.instance = 0x01;
6894
6895 if (status)
6896 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6897 mgmt_status(status));
6898 else
6899 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6900 mgmt_status(status), &rp, sizeof(rp));
6901
6902 mgmt_pending_remove(cmd);
6903
6904unlock:
6905 hci_dev_unlock(hdev);
6906}
6907
Florian Grandel5d900e42015-06-18 03:16:35 +02006908void mgmt_adv_timeout_expired(struct hci_dev *hdev)
Arman Uguray912098a2015-03-23 15:57:15 -07006909{
Florian Grandel5d900e42015-06-18 03:16:35 +02006910 hdev->adv_instance_timeout = 0;
Arman Uguray912098a2015-03-23 15:57:15 -07006911
6912 hci_dev_lock(hdev);
6913 clear_adv_instance(hdev);
6914 hci_dev_unlock(hdev);
6915}
6916
Arman Uguray24b4f382015-03-23 15:57:12 -07006917static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6918 void *data, u16 data_len)
6919{
6920 struct mgmt_cp_add_advertising *cp = data;
6921 struct mgmt_rp_add_advertising rp;
6922 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006923 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006924 u8 status;
Arman Uguray912098a2015-03-23 15:57:15 -07006925 u16 timeout;
Arman Uguray24b4f382015-03-23 15:57:12 -07006926 int err;
6927 struct mgmt_pending_cmd *cmd;
6928 struct hci_request req;
6929
6930 BT_DBG("%s", hdev->name);
6931
6932 status = mgmt_le_support(hdev);
6933 if (status)
6934 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6935 status);
6936
6937 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006938 timeout = __le16_to_cpu(cp->timeout);
Arman Uguray24b4f382015-03-23 15:57:12 -07006939
Arman Uguray089fa8c2015-03-25 18:53:45 -07006940 /* The current implementation only supports adding one instance and only
6941 * a subset of the specified flags.
6942 */
6943 supported_flags = get_supported_adv_flags(hdev);
6944 if (cp->instance != 0x01 || (flags & ~supported_flags))
Arman Uguray24b4f382015-03-23 15:57:12 -07006945 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6946 MGMT_STATUS_INVALID_PARAMS);
6947
6948 hci_dev_lock(hdev);
6949
Arman Uguray912098a2015-03-23 15:57:15 -07006950 if (timeout && !hdev_is_powered(hdev)) {
6951 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6952 MGMT_STATUS_REJECTED);
6953 goto unlock;
6954 }
6955
Arman Uguray24b4f382015-03-23 15:57:12 -07006956 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006957 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006958 pending_find(MGMT_OP_SET_LE, hdev)) {
6959 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6960 MGMT_STATUS_BUSY);
6961 goto unlock;
6962 }
6963
Arman Ugurayb44133f2015-03-25 18:53:41 -07006964 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006965 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006966 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006967 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6968 MGMT_STATUS_INVALID_PARAMS);
6969 goto unlock;
6970 }
6971
6972 hdev->adv_instance.flags = flags;
6973 hdev->adv_instance.adv_data_len = cp->adv_data_len;
6974 hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
6975
6976 if (cp->adv_data_len)
6977 memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
6978
6979 if (cp->scan_rsp_len)
6980 memcpy(hdev->adv_instance.scan_rsp_data,
6981 cp->data + cp->adv_data_len, cp->scan_rsp_len);
6982
Florian Grandel5d900e42015-06-18 03:16:35 +02006983 if (hdev->adv_instance_timeout)
6984 cancel_delayed_work(&hdev->adv_instance_expire);
Arman Uguray912098a2015-03-23 15:57:15 -07006985
Florian Grandel5d900e42015-06-18 03:16:35 +02006986 hdev->adv_instance_timeout = timeout;
Arman Uguray912098a2015-03-23 15:57:15 -07006987
6988 if (timeout)
6989 queue_delayed_work(hdev->workqueue,
Florian Grandel5d900e42015-06-18 03:16:35 +02006990 &hdev->adv_instance_expire,
Arman Uguray912098a2015-03-23 15:57:15 -07006991 msecs_to_jiffies(timeout * 1000));
6992
Arman Uguray24b4f382015-03-23 15:57:12 -07006993 if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
6994 advertising_added(sk, hdev, 1);
6995
6996 /* If the HCI_ADVERTISING flag is set or the device isn't powered then
6997 * we have no HCI communication to make. Simply return.
6998 */
6999 if (!hdev_is_powered(hdev) ||
7000 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
7001 rp.instance = 0x01;
7002 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
7003 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7004 goto unlock;
7005 }
7006
7007 /* We're good to go, update advertising data, parameters, and start
7008 * advertising.
7009 */
7010 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
7011 data_len);
7012 if (!cmd) {
7013 err = -ENOMEM;
7014 goto unlock;
7015 }
7016
7017 hci_req_init(&req, hdev);
7018
7019 update_adv_data(&req);
Arman Uguray4117ed72015-03-23 15:57:14 -07007020 update_scan_rsp_data(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07007021 enable_advertising(&req);
7022
7023 err = hci_req_run(&req, add_advertising_complete);
7024 if (err < 0)
7025 mgmt_pending_remove(cmd);
7026
7027unlock:
7028 hci_dev_unlock(hdev);
7029
7030 return err;
7031}
7032
Arman Ugurayda9293352015-03-23 15:57:13 -07007033static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7034 u16 opcode)
7035{
7036 struct mgmt_pending_cmd *cmd;
7037 struct mgmt_rp_remove_advertising rp;
7038
7039 BT_DBG("status %d", status);
7040
7041 hci_dev_lock(hdev);
7042
7043 /* A failure status here only means that we failed to disable
7044 * advertising. Otherwise, the advertising instance has been removed,
7045 * so report success.
7046 */
7047 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
7048 if (!cmd)
7049 goto unlock;
7050
7051 rp.instance = 1;
7052
7053 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7054 &rp, sizeof(rp));
7055 mgmt_pending_remove(cmd);
7056
7057unlock:
7058 hci_dev_unlock(hdev);
7059}
7060
7061static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7062 void *data, u16 data_len)
7063{
7064 struct mgmt_cp_remove_advertising *cp = data;
7065 struct mgmt_rp_remove_advertising rp;
7066 int err;
7067 struct mgmt_pending_cmd *cmd;
7068 struct hci_request req;
7069
7070 BT_DBG("%s", hdev->name);
7071
7072 /* The current implementation only allows modifying instance no 1. A
7073 * value of 0 indicates that all instances should be cleared.
7074 */
7075 if (cp->instance > 1)
7076 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7077 MGMT_STATUS_INVALID_PARAMS);
7078
7079 hci_dev_lock(hdev);
7080
7081 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7082 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7083 pending_find(MGMT_OP_SET_LE, hdev)) {
7084 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7085 MGMT_STATUS_BUSY);
7086 goto unlock;
7087 }
7088
7089 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
7090 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7091 MGMT_STATUS_INVALID_PARAMS);
7092 goto unlock;
7093 }
7094
Florian Grandel5d900e42015-06-18 03:16:35 +02007095 if (hdev->adv_instance_timeout)
7096 cancel_delayed_work(&hdev->adv_instance_expire);
Arman Uguray912098a2015-03-23 15:57:15 -07007097
Arman Ugurayda9293352015-03-23 15:57:13 -07007098 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
7099
7100 advertising_removed(sk, hdev, 1);
7101
7102 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
7103
7104 /* If the HCI_ADVERTISING flag is set or the device isn't powered then
7105 * we have no HCI communication to make. Simply return.
7106 */
7107 if (!hdev_is_powered(hdev) ||
7108 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
7109 rp.instance = 1;
7110 err = mgmt_cmd_complete(sk, hdev->id,
7111 MGMT_OP_REMOVE_ADVERTISING,
7112 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7113 goto unlock;
7114 }
7115
7116 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
7117 data_len);
7118 if (!cmd) {
7119 err = -ENOMEM;
7120 goto unlock;
7121 }
7122
7123 hci_req_init(&req, hdev);
7124 disable_advertising(&req);
7125
7126 err = hci_req_run(&req, remove_advertising_complete);
7127 if (err < 0)
7128 mgmt_pending_remove(cmd);
7129
7130unlock:
7131 hci_dev_unlock(hdev);
7132
7133 return err;
7134}
7135
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007136static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007137 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007138 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007139 HCI_MGMT_NO_HDEV |
7140 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007141 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007142 HCI_MGMT_NO_HDEV |
7143 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007144 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007145 HCI_MGMT_NO_HDEV |
7146 HCI_MGMT_UNTRUSTED },
7147 { read_controller_info, MGMT_READ_INFO_SIZE,
7148 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007149 { set_powered, MGMT_SETTING_SIZE },
7150 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
7151 { set_connectable, MGMT_SETTING_SIZE },
7152 { set_fast_connectable, MGMT_SETTING_SIZE },
7153 { set_bondable, MGMT_SETTING_SIZE },
7154 { set_link_security, MGMT_SETTING_SIZE },
7155 { set_ssp, MGMT_SETTING_SIZE },
7156 { set_hs, MGMT_SETTING_SIZE },
7157 { set_le, MGMT_SETTING_SIZE },
7158 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
7159 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
7160 { add_uuid, MGMT_ADD_UUID_SIZE },
7161 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007162 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
7163 HCI_MGMT_VAR_LEN },
7164 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
7165 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007166 { disconnect, MGMT_DISCONNECT_SIZE },
7167 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
7168 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
7169 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
7170 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
7171 { pair_device, MGMT_PAIR_DEVICE_SIZE },
7172 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
7173 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
7174 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
7175 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
7176 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
7177 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007178 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
7179 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
7180 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007181 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
7182 { start_discovery, MGMT_START_DISCOVERY_SIZE },
7183 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
7184 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
7185 { block_device, MGMT_BLOCK_DEVICE_SIZE },
7186 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
7187 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
7188 { set_advertising, MGMT_SETTING_SIZE },
7189 { set_bredr, MGMT_SETTING_SIZE },
7190 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
7191 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
7192 { set_secure_conn, MGMT_SETTING_SIZE },
7193 { set_debug_keys, MGMT_SETTING_SIZE },
7194 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007195 { load_irks, MGMT_LOAD_IRKS_SIZE,
7196 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07007197 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
7198 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
7199 { add_device, MGMT_ADD_DEVICE_SIZE },
7200 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007201 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
7202 HCI_MGMT_VAR_LEN },
7203 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007204 HCI_MGMT_NO_HDEV |
7205 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007206 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007207 HCI_MGMT_UNCONFIGURED |
7208 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02007209 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
7210 HCI_MGMT_UNCONFIGURED },
7211 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
7212 HCI_MGMT_UNCONFIGURED },
7213 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
7214 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07007215 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07007216 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07007217 HCI_MGMT_NO_HDEV |
7218 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07007219 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07007220 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7221 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07007222 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02007223};
7224
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007225void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007226{
Marcel Holtmannced85542015-03-14 19:27:56 -07007227 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03007228
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007229 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7230 return;
7231
Marcel Holtmannf9207332015-03-14 19:27:55 -07007232 switch (hdev->dev_type) {
7233 case HCI_BREDR:
7234 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7235 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
7236 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007237 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007238 } else {
7239 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
7240 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007241 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007242 }
7243 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007244 case HCI_AMP:
7245 ev.type = 0x02;
7246 break;
7247 default:
7248 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007249 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007250
7251 ev.bus = hdev->bus;
7252
7253 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
7254 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007255}
7256
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07007257void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02007258{
Marcel Holtmannced85542015-03-14 19:27:56 -07007259 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02007260 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007261
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02007262 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
7263 return;
7264
Marcel Holtmannf9207332015-03-14 19:27:55 -07007265 switch (hdev->dev_type) {
7266 case HCI_BREDR:
7267 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02007268
Marcel Holtmannf9207332015-03-14 19:27:55 -07007269 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
7270 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
7271 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007272 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007273 } else {
7274 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
7275 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07007276 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007277 }
7278 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07007279 case HCI_AMP:
7280 ev.type = 0x02;
7281 break;
7282 default:
7283 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07007284 }
Marcel Holtmannced85542015-03-14 19:27:56 -07007285
7286 ev.bus = hdev->bus;
7287
7288 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
7289 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007290}
7291
Andre Guedes6046dc32014-02-26 20:21:51 -03007292/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02007293static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03007294{
Johan Hedberg2cf22212014-12-19 22:26:00 +02007295 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03007296 struct hci_conn_params *p;
7297
7298 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03007299 /* Needed for AUTO_OFF case where might not "really"
7300 * have been powered off.
7301 */
7302 list_del_init(&p->action);
7303
7304 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02007305 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03007306 case HCI_AUTO_CONN_ALWAYS:
7307 list_add(&p->action, &hdev->pend_le_conns);
7308 break;
7309 case HCI_AUTO_CONN_REPORT:
7310 list_add(&p->action, &hdev->pend_le_reports);
7311 break;
7312 default:
7313 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007314 }
Andre Guedes6046dc32014-02-26 20:21:51 -03007315 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02007316
Johan Hedberg2cf22212014-12-19 22:26:00 +02007317 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03007318}
7319
Marcel Holtmann1904a852015-01-11 13:50:44 -08007320static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05007321{
7322 struct cmd_lookup match = { NULL, hdev };
7323
7324 BT_DBG("status 0x%02x", status);
7325
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08007326 if (!status) {
7327 /* Register the available SMP channels (BR/EDR and LE) only
7328 * when successfully powering on the controller. This late
7329 * registration is required so that LE SMP can clearly
7330 * decide if the public address or static address is used.
7331 */
7332 smp_register(hdev);
7333 }
7334
Johan Hedberg229ab392013-03-15 17:06:53 -05007335 hci_dev_lock(hdev);
7336
7337 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
7338
7339 new_settings(hdev, match.sk);
7340
7341 hci_dev_unlock(hdev);
7342
7343 if (match.sk)
7344 sock_put(match.sk);
7345}
7346
Johan Hedberg70da6242013-03-15 17:06:51 -05007347static int powered_update_hci(struct hci_dev *hdev)
7348{
Johan Hedberg890ea892013-03-15 17:06:52 -05007349 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05007350 u8 link_sec;
7351
Johan Hedberg890ea892013-03-15 17:06:52 -05007352 hci_req_init(&req, hdev);
7353
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007354 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05007355 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08007356 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05007357
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08007358 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05007359
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08007360 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
7361 u8 support = 0x01;
7362
7363 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
7364 sizeof(support), &support);
7365 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02007366 }
7367
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007368 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03007369 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05007370 struct hci_cp_write_le_host_supported cp;
7371
Marcel Holtmann32226e42014-07-24 20:04:16 +02007372 cp.le = 0x01;
7373 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05007374
7375 /* Check first if we already have the right
7376 * host state (host features set)
7377 */
7378 if (cp.le != lmp_host_le_capable(hdev) ||
7379 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007380 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
7381 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05007382 }
7383
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07007384 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07007385 /* Make sure the controller has a good default for
7386 * advertising data. This also applies to the case
7387 * where BR/EDR was toggled during the AUTO_OFF phase.
7388 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007389 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07007390 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07007391 update_scan_rsp_data(&req);
7392 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07007393
Arman Uguray24b4f382015-03-23 15:57:12 -07007394 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
7395 hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07007396 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02007397
7398 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03007399 }
7400
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007401 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05007402 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05007403 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
7404 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05007405
7406 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007407 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02007408 write_fast_connectable(&req, true);
7409 else
7410 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02007411 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05007412 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05007413 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05007414 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05007415 }
7416
Johan Hedberg229ab392013-03-15 17:06:53 -05007417 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05007418}
7419
Johan Hedberg744cf192011-11-08 20:40:14 +02007420int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02007421{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02007422 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02007423 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02007424 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02007425
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007426 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02007427 return 0;
7428
Johan Hedberg5e5282b2012-02-21 16:01:30 +02007429 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05007430 if (powered_update_hci(hdev) == 0)
7431 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02007432
Johan Hedberg229ab392013-03-15 17:06:53 -05007433 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
7434 &match);
7435 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02007436 }
7437
Johan Hedberg229ab392013-03-15 17:06:53 -05007438 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02007439
7440 /* If the power off is because of hdev unregistration let
7441 * use the appropriate INVALID_INDEX status. Otherwise use
7442 * NOT_POWERED. We cover both scenarios here since later in
7443 * mgmt_index_removed() any hci_conn callbacks will have already
7444 * been triggered, potentially causing misleading DISCONNECTED
7445 * status responses.
7446 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007447 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02007448 status = MGMT_STATUS_INVALID_INDEX;
7449 else
7450 status = MGMT_STATUS_NOT_POWERED;
7451
7452 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007453
7454 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007455 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7456 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05007457
7458new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02007459 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007460
7461 if (match.sk)
7462 sock_put(match.sk);
7463
Johan Hedberg7bb895d2012-02-17 01:20:00 +02007464 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02007465}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007466
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007467void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007468{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007469 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007470 u8 status;
7471
Johan Hedberg333ae952015-03-17 13:48:47 +02007472 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007473 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007474 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007475
7476 if (err == -ERFKILL)
7477 status = MGMT_STATUS_RFKILLED;
7478 else
7479 status = MGMT_STATUS_FAILED;
7480
Johan Hedberga69e8372015-03-06 21:08:53 +02007481 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007482
7483 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007484}
7485
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007486void mgmt_discoverable_timeout(struct hci_dev *hdev)
7487{
7488 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007489
7490 hci_dev_lock(hdev);
7491
7492 /* When discoverable timeout triggers, then just make sure
7493 * the limited discoverable flag is cleared. Even in the case
7494 * of a timeout triggered from general discoverable, it is
7495 * safe to unconditionally clear the flag.
7496 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007497 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
7498 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007499
7500 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007501 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03007502 u8 scan = SCAN_PAGE;
7503 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
7504 sizeof(scan), &scan);
7505 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007506 update_class(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07007507
7508 /* Advertising instances don't use the global discoverable setting, so
7509 * only update AD if advertising was enabled using Set Advertising.
7510 */
7511 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7512 update_adv_data(&req);
7513
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007514 hci_req_run(&req, NULL);
7515
7516 hdev->discov_timeout = 0;
7517
Johan Hedberg9a43e252013-10-20 19:00:07 +03007518 new_settings(hdev, NULL);
7519
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007520 hci_dev_unlock(hdev);
7521}
7522
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007523void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7524 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007525{
Johan Hedberg86742e12011-11-07 23:13:38 +02007526 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007527
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007528 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007529
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007530 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007531 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007532 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007533 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007534 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007535 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007536
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007537 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007538}
Johan Hedbergf7520542011-01-20 12:34:39 +02007539
Johan Hedbergd7b25452014-05-23 13:19:53 +03007540static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7541{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007542 switch (ltk->type) {
7543 case SMP_LTK:
7544 case SMP_LTK_SLAVE:
7545 if (ltk->authenticated)
7546 return MGMT_LTK_AUTHENTICATED;
7547 return MGMT_LTK_UNAUTHENTICATED;
7548 case SMP_LTK_P256:
7549 if (ltk->authenticated)
7550 return MGMT_LTK_P256_AUTH;
7551 return MGMT_LTK_P256_UNAUTH;
7552 case SMP_LTK_P256_DEBUG:
7553 return MGMT_LTK_P256_DEBUG;
7554 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007555
7556 return MGMT_LTK_UNAUTHENTICATED;
7557}
7558
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007559void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007560{
7561 struct mgmt_ev_new_long_term_key ev;
7562
7563 memset(&ev, 0, sizeof(ev));
7564
Marcel Holtmann5192d302014-02-19 17:11:58 -08007565 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007566 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08007567 * to store long term keys. Their addresses will change the
7568 * next time around.
7569 *
7570 * Only when a remote device provides an identity address
7571 * make sure the long term key is stored. If the remote
7572 * identity is known, the long term keys are internally
7573 * mapped to the identity address. So allow static random
7574 * and public addresses here.
7575 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007576 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7577 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7578 ev.store_hint = 0x00;
7579 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007580 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007581
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007582 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007583 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007584 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007585 ev.key.enc_size = key->enc_size;
7586 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007587 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007588
Johan Hedberg2ceba532014-06-16 19:25:16 +03007589 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007590 ev.key.master = 1;
7591
Johan Hedberg1fc62c52015-06-10 11:11:20 +03007592 /* Make sure we copy only the significant bytes based on the
7593 * encryption key size, and set the rest of the value to zeroes.
7594 */
7595 memcpy(ev.key.val, key->val, sizeof(key->enc_size));
7596 memset(ev.key.val + key->enc_size, 0,
7597 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007598
Marcel Holtmann083368f2013-10-15 14:26:29 -07007599 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007600}
7601
Johan Hedberg95fbac82014-02-19 15:18:31 +02007602void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
7603{
7604 struct mgmt_ev_new_irk ev;
7605
7606 memset(&ev, 0, sizeof(ev));
7607
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007608 /* For identity resolving keys from devices that are already
7609 * using a public address or static random address, do not
7610 * ask for storing this key. The identity resolving key really
Florian Grandelf72186d2015-05-26 03:31:09 +02007611 * is only mandatory for devices using resolvable random
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007612 * addresses.
7613 *
7614 * Storing all identity resolving keys has the downside that
7615 * they will be also loaded on next boot of they system. More
7616 * identity resolving keys, means more time during scanning is
7617 * needed to actually resolve these addresses.
7618 */
7619 if (bacmp(&irk->rpa, BDADDR_ANY))
7620 ev.store_hint = 0x01;
7621 else
7622 ev.store_hint = 0x00;
7623
Johan Hedberg95fbac82014-02-19 15:18:31 +02007624 bacpy(&ev.rpa, &irk->rpa);
7625 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7626 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7627 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7628
7629 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7630}
7631
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007632void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7633 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007634{
7635 struct mgmt_ev_new_csrk ev;
7636
7637 memset(&ev, 0, sizeof(ev));
7638
7639 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02007640 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007641 * to store signature resolving keys. Their addresses will change
7642 * the next time around.
7643 *
7644 * Only when a remote device provides an identity address
7645 * make sure the signature resolving key is stored. So allow
7646 * static random and public addresses here.
7647 */
7648 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7649 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7650 ev.store_hint = 0x00;
7651 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007652 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007653
7654 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7655 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007656 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007657 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7658
7659 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7660}
7661
Andre Guedesffb5a8272014-07-01 18:10:11 -03007662void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007663 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7664 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007665{
7666 struct mgmt_ev_new_conn_param ev;
7667
Johan Hedbergc103aea2014-07-02 17:37:34 +03007668 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7669 return;
7670
Andre Guedesffb5a8272014-07-01 18:10:11 -03007671 memset(&ev, 0, sizeof(ev));
7672 bacpy(&ev.addr.bdaddr, bdaddr);
7673 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007674 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007675 ev.min_interval = cpu_to_le16(min_interval);
7676 ev.max_interval = cpu_to_le16(max_interval);
7677 ev.latency = cpu_to_le16(latency);
7678 ev.timeout = cpu_to_le16(timeout);
7679
7680 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7681}
7682
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007683void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7684 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007685{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007686 char buf[512];
7687 struct mgmt_ev_device_connected *ev = (void *) buf;
7688 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007689
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007690 bacpy(&ev->addr.bdaddr, &conn->dst);
7691 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007692
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007693 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007694
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007695 /* We must ensure that the EIR Data fields are ordered and
7696 * unique. Keep it simple for now and avoid the problem by not
7697 * adding any BR/EDR data to the LE adv.
7698 */
7699 if (conn->le_adv_data_len > 0) {
7700 memcpy(&ev->eir[eir_len],
7701 conn->le_adv_data, conn->le_adv_data_len);
7702 eir_len = conn->le_adv_data_len;
7703 } else {
7704 if (name_len > 0)
7705 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7706 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007707
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007708 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007709 eir_len = eir_append_data(ev->eir, eir_len,
7710 EIR_CLASS_OF_DEV,
7711 conn->dev_class, 3);
7712 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007713
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007714 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007715
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007716 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7717 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007718}
7719
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007720static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007721{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007722 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007723
Johan Hedbergf5818c22014-12-05 13:36:02 +02007724 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007725
7726 *sk = cmd->sk;
7727 sock_hold(*sk);
7728
Johan Hedberga664b5b2011-02-19 12:06:02 -03007729 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007730}
7731
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007732static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007733{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007734 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007735 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007736
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007737 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7738
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007739 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007740 mgmt_pending_remove(cmd);
7741}
7742
Johan Hedberg84c61d92014-08-01 11:13:30 +03007743bool mgmt_powering_down(struct hci_dev *hdev)
7744{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007745 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007746 struct mgmt_mode *cp;
7747
Johan Hedberg333ae952015-03-17 13:48:47 +02007748 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007749 if (!cmd)
7750 return false;
7751
7752 cp = cmd->param;
7753 if (!cp->val)
7754 return true;
7755
7756 return false;
7757}
7758
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007759void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007760 u8 link_type, u8 addr_type, u8 reason,
7761 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007762{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007763 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007764 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007765
Johan Hedberg84c61d92014-08-01 11:13:30 +03007766 /* The connection is still in hci_conn_hash so test for 1
7767 * instead of 0 to know if this is the last one.
7768 */
7769 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7770 cancel_delayed_work(&hdev->power_off);
7771 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007772 }
7773
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007774 if (!mgmt_connected)
7775 return;
7776
Andre Guedes57eb7762013-10-30 19:01:41 -03007777 if (link_type != ACL_LINK && link_type != LE_LINK)
7778 return;
7779
Johan Hedberg744cf192011-11-08 20:40:14 +02007780 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007781
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007782 bacpy(&ev.addr.bdaddr, bdaddr);
7783 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7784 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007785
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007786 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007787
7788 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007789 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007790
Johan Hedberg124f6e32012-02-09 13:50:12 +02007791 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007792 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007793}
7794
Marcel Holtmann78929242013-10-06 23:55:47 -07007795void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7796 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007797{
Andre Guedes3655bba2013-10-30 19:01:40 -03007798 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7799 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007800 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007801
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007802 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7803 hdev);
7804
Johan Hedberg333ae952015-03-17 13:48:47 +02007805 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007806 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007807 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007808
Andre Guedes3655bba2013-10-30 19:01:40 -03007809 cp = cmd->param;
7810
7811 if (bacmp(bdaddr, &cp->addr.bdaddr))
7812 return;
7813
7814 if (cp->addr.type != bdaddr_type)
7815 return;
7816
Johan Hedbergf5818c22014-12-05 13:36:02 +02007817 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007818 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007819}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007820
Marcel Holtmann445608d2013-10-06 23:55:48 -07007821void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7822 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007823{
7824 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007825
Johan Hedberg84c61d92014-08-01 11:13:30 +03007826 /* The connection is still in hci_conn_hash so test for 1
7827 * instead of 0 to know if this is the last one.
7828 */
7829 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7830 cancel_delayed_work(&hdev->power_off);
7831 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007832 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007833
Johan Hedberg4c659c32011-11-07 23:13:39 +02007834 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007835 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007836 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007837
Marcel Holtmann445608d2013-10-06 23:55:48 -07007838 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007839}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007840
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007841void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007842{
7843 struct mgmt_ev_pin_code_request ev;
7844
Johan Hedbergd8457692012-02-17 14:24:57 +02007845 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007846 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007847 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007848
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007849 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007850}
7851
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007852void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7853 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007854{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007855 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007856
Johan Hedberg333ae952015-03-17 13:48:47 +02007857 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007858 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007859 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007860
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007861 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007862 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007863}
7864
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007865void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7866 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007867{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007868 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007869
Johan Hedberg333ae952015-03-17 13:48:47 +02007870 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007871 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007872 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007873
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007874 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007875 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007876}
Johan Hedberga5c29682011-02-19 12:05:57 -03007877
Johan Hedberg744cf192011-11-08 20:40:14 +02007878int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007879 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007880 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007881{
7882 struct mgmt_ev_user_confirm_request ev;
7883
Johan Hedberg744cf192011-11-08 20:40:14 +02007884 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007885
Johan Hedberg272d90d2012-02-09 15:26:12 +02007886 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007887 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007888 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007889 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007890
Johan Hedberg744cf192011-11-08 20:40:14 +02007891 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007892 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007893}
7894
Johan Hedberg272d90d2012-02-09 15:26:12 +02007895int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007896 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007897{
7898 struct mgmt_ev_user_passkey_request ev;
7899
7900 BT_DBG("%s", hdev->name);
7901
Johan Hedberg272d90d2012-02-09 15:26:12 +02007902 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007903 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007904
7905 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007906 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007907}
7908
Brian Gix0df4c182011-11-16 13:53:13 -08007909static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007910 u8 link_type, u8 addr_type, u8 status,
7911 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007912{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007913 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007914
Johan Hedberg333ae952015-03-17 13:48:47 +02007915 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007916 if (!cmd)
7917 return -ENOENT;
7918
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007919 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007920 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007921
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007922 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007923}
7924
Johan Hedberg744cf192011-11-08 20:40:14 +02007925int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007926 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007927{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007928 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007929 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007930}
7931
Johan Hedberg272d90d2012-02-09 15:26:12 +02007932int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007933 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007934{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007935 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007936 status,
7937 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007938}
Johan Hedberg2a611692011-02-19 12:06:00 -03007939
Brian Gix604086b2011-11-23 08:28:33 -08007940int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007941 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007942{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007943 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007944 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007945}
7946
Johan Hedberg272d90d2012-02-09 15:26:12 +02007947int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007948 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007949{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007950 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007951 status,
7952 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007953}
7954
Johan Hedberg92a25252012-09-06 18:39:26 +03007955int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7956 u8 link_type, u8 addr_type, u32 passkey,
7957 u8 entered)
7958{
7959 struct mgmt_ev_passkey_notify ev;
7960
7961 BT_DBG("%s", hdev->name);
7962
7963 bacpy(&ev.addr.bdaddr, bdaddr);
7964 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7965 ev.passkey = __cpu_to_le32(passkey);
7966 ev.entered = entered;
7967
7968 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7969}
7970
Johan Hedberge1e930f2014-09-08 17:09:49 -07007971void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007972{
7973 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007974 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007975 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007976
Johan Hedberge1e930f2014-09-08 17:09:49 -07007977 bacpy(&ev.addr.bdaddr, &conn->dst);
7978 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7979 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007980
Johan Hedberge1e930f2014-09-08 17:09:49 -07007981 cmd = find_pairing(conn);
7982
7983 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7984 cmd ? cmd->sk : NULL);
7985
Johan Hedberga511b352014-12-11 21:45:45 +02007986 if (cmd) {
7987 cmd->cmd_complete(cmd, status);
7988 mgmt_pending_remove(cmd);
7989 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007990}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007991
Marcel Holtmann464996a2013-10-15 14:26:24 -07007992void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007993{
7994 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007995 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007996
7997 if (status) {
7998 u8 mgmt_err = mgmt_status(status);
7999 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008000 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008001 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008002 }
8003
Marcel Holtmann464996a2013-10-15 14:26:24 -07008004 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07008005 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07008006 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008007 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02008008
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008009 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008010 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008011
Johan Hedberg47990ea2012-02-22 11:58:37 +02008012 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07008013 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008014
8015 if (match.sk)
8016 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02008017}
8018
Johan Hedberg890ea892013-03-15 17:06:52 -05008019static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02008020{
Johan Hedberg890ea892013-03-15 17:06:52 -05008021 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008022 struct hci_cp_write_eir cp;
8023
Johan Hedberg976eb202012-10-24 21:12:01 +03008024 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05008025 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02008026
Johan Hedbergc80da272012-02-22 15:38:48 +02008027 memset(hdev->eir, 0, sizeof(hdev->eir));
8028
Johan Hedbergcacaf522012-02-21 00:52:42 +02008029 memset(&cp, 0, sizeof(cp));
8030
Johan Hedberg890ea892013-03-15 17:06:52 -05008031 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02008032}
8033
Marcel Holtmann3e248562013-10-15 14:26:25 -07008034void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008035{
8036 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05008037 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008038 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008039
8040 if (status) {
8041 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008042
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008043 if (enable && hci_dev_test_and_clear_flag(hdev,
8044 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008045 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008046 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008047 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008048
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008049 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
8050 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07008051 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008052 }
8053
8054 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07008055 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008056 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008057 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008058 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07008059 changed = hci_dev_test_and_clear_flag(hdev,
8060 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07008061 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07008062 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008063 }
8064
8065 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
8066
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02008067 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07008068 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008069
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02008070 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008071 sock_put(match.sk);
8072
Johan Hedberg890ea892013-03-15 17:06:52 -05008073 hci_req_init(&req, hdev);
8074
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008075 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
8076 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03008077 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
8078 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05008079 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008080 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05008081 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03008082 }
Johan Hedberg890ea892013-03-15 17:06:52 -05008083
8084 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02008085}
8086
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008087static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02008088{
8089 struct cmd_lookup *match = data;
8090
Johan Hedberg90e70452012-02-23 23:09:40 +02008091 if (match->sk == NULL) {
8092 match->sk = cmd->sk;
8093 sock_hold(match->sk);
8094 }
Johan Hedberg90e70452012-02-23 23:09:40 +02008095}
8096
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07008097void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
8098 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008099{
Johan Hedberg90e70452012-02-23 23:09:40 +02008100 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008101
Johan Hedberg92da6092013-03-15 17:06:55 -05008102 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
8103 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
8104 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02008105
8106 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07008107 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
8108 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02008109
8110 if (match.sk)
8111 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01008112}
8113
Marcel Holtmann7667da32013-10-15 14:26:27 -07008114void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02008115{
Johan Hedbergb312b1612011-03-16 14:29:37 +02008116 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02008117 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008118
Johan Hedberg13928972013-03-15 17:07:00 -05008119 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07008120 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008121
8122 memset(&ev, 0, sizeof(ev));
8123 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02008124 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008125
Johan Hedberg333ae952015-03-17 13:48:47 +02008126 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05008127 if (!cmd) {
8128 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02008129
Johan Hedberg13928972013-03-15 17:07:00 -05008130 /* If this is a HCI command related to powering on the
8131 * HCI dev don't send any mgmt signals.
8132 */
Johan Hedberg333ae952015-03-17 13:48:47 +02008133 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07008134 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02008135 }
8136
Marcel Holtmannf6b77122015-03-14 19:28:05 -07008137 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
8138 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02008139}
Szymon Jancc35938b2011-03-22 13:12:21 +01008140
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008141static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
8142{
8143 int i;
8144
8145 for (i = 0; i < uuid_count; i++) {
8146 if (!memcmp(uuid, uuids[i], 16))
8147 return true;
8148 }
8149
8150 return false;
8151}
8152
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008153static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
8154{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008155 u16 parsed = 0;
8156
8157 while (parsed < eir_len) {
8158 u8 field_len = eir[0];
8159 u8 uuid[16];
8160 int i;
8161
8162 if (field_len == 0)
8163 break;
8164
8165 if (eir_len - parsed < field_len + 1)
8166 break;
8167
8168 switch (eir[1]) {
8169 case EIR_UUID16_ALL:
8170 case EIR_UUID16_SOME:
8171 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008172 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008173 uuid[13] = eir[i + 3];
8174 uuid[12] = eir[i + 2];
8175 if (has_uuid(uuid, uuid_count, uuids))
8176 return true;
8177 }
8178 break;
8179 case EIR_UUID32_ALL:
8180 case EIR_UUID32_SOME:
8181 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02008182 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01008183 uuid[15] = eir[i + 5];
8184 uuid[14] = eir[i + 4];
8185 uuid[13] = eir[i + 3];
8186 uuid[12] = eir[i + 2];
8187 if (has_uuid(uuid, uuid_count, uuids))
8188 return true;
8189 }
8190 break;
8191 case EIR_UUID128_ALL:
8192 case EIR_UUID128_SOME:
8193 for (i = 0; i + 17 <= field_len; i += 16) {
8194 memcpy(uuid, eir + i + 2, 16);
8195 if (has_uuid(uuid, uuid_count, uuids))
8196 return true;
8197 }
8198 break;
8199 }
8200
8201 parsed += field_len + 1;
8202 eir += field_len + 1;
8203 }
8204
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008205 return false;
8206}
8207
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008208static void restart_le_scan(struct hci_dev *hdev)
8209{
8210 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07008211 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008212 return;
8213
8214 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
8215 hdev->discovery.scan_start +
8216 hdev->discovery.scan_duration))
8217 return;
8218
8219 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
8220 DISCOV_LE_RESTART_DELAY);
8221}
8222
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008223static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
8224 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
8225{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008226 /* If a RSSI threshold has been specified, and
8227 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
8228 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
8229 * is set, let it through for further processing, as we might need to
8230 * restart the scan.
8231 *
8232 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
8233 * the results are also dropped.
8234 */
8235 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8236 (rssi == HCI_RSSI_INVALID ||
8237 (rssi < hdev->discovery.rssi &&
8238 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
8239 return false;
8240
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008241 if (hdev->discovery.uuid_count != 0) {
8242 /* If a list of UUIDs is provided in filter, results with no
8243 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008244 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008245 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
8246 hdev->discovery.uuids) &&
8247 !eir_has_uuids(scan_rsp, scan_rsp_len,
8248 hdev->discovery.uuid_count,
8249 hdev->discovery.uuids))
8250 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008251 }
8252
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008253 /* If duplicate filtering does not report RSSI changes, then restart
8254 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008255 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08008256 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
8257 restart_le_scan(hdev);
8258
8259 /* Validate RSSI value against the RSSI threshold once more. */
8260 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
8261 rssi < hdev->discovery.rssi)
8262 return false;
8263 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008264
8265 return true;
8266}
8267
Marcel Holtmann901801b2013-10-06 23:55:51 -07008268void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02008269 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
8270 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03008271{
Johan Hedberge319d2e2012-01-15 19:51:59 +02008272 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008273 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02008274 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03008275
Johan Hedberg75ce2082014-07-02 22:42:01 +03008276 /* Don't send events for a non-kernel initiated discovery. With
8277 * LE one exception is if we have pend_le_reports > 0 in which
8278 * case we're doing passive scanning and want these events.
8279 */
8280 if (!hci_discovery_active(hdev)) {
8281 if (link_type == ACL_LINK)
8282 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03008283 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03008284 return;
8285 }
Andre Guedes12602d02013-04-30 15:29:40 -03008286
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08008287 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008288 /* We are using service discovery */
8289 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
8290 scan_rsp_len))
8291 return;
8292 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01008293
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008294 /* Make sure that the buffer is big enough. The 5 extra bytes
8295 * are for the potential CoD field.
8296 */
8297 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07008298 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03008299
Johan Hedberg1dc06092012-01-15 21:01:23 +02008300 memset(buf, 0, sizeof(buf));
8301
Marcel Holtmannda25cf62014-12-05 13:03:35 +01008302 /* In case of device discovery with BR/EDR devices (pre 1.2), the
8303 * RSSI value was reported as 0 when not available. This behavior
8304 * is kept when using device discovery. This is required for full
8305 * backwards compatibility with the API.
8306 *
8307 * However when using service discovery, the value 127 will be
8308 * returned when the RSSI is not available.
8309 */
Szymon Janc91200e92015-01-22 16:57:05 +01008310 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
8311 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01008312 rssi = 0;
8313
Johan Hedberg841c5642014-07-07 12:45:54 +03008314 bacpy(&ev->addr.bdaddr, bdaddr);
8315 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02008316 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02008317 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03008318
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008319 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008320 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02008321 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03008322
Johan Hedberg1dc06092012-01-15 21:01:23 +02008323 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
8324 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008325 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02008326
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08008327 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01008328 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008329 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08008330
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02008331 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
8332 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03008333
Marcel Holtmann901801b2013-10-06 23:55:51 -07008334 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03008335}
Johan Hedberga88a9652011-03-30 13:18:12 +03008336
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008337void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
8338 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03008339{
Johan Hedbergb644ba32012-01-17 21:48:47 +02008340 struct mgmt_ev_device_found *ev;
8341 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
8342 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03008343
Johan Hedbergb644ba32012-01-17 21:48:47 +02008344 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03008345
Johan Hedbergb644ba32012-01-17 21:48:47 +02008346 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03008347
Johan Hedbergb644ba32012-01-17 21:48:47 +02008348 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03008349 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008350 ev->rssi = rssi;
8351
8352 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03008353 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008354
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02008355 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02008356
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07008357 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03008358}
Johan Hedberg314b2382011-04-27 10:29:57 -04008359
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008360void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04008361{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008362 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02008363
Andre Guedes343fb142011-11-22 17:14:19 -03008364 BT_DBG("%s discovering %u", hdev->name, discovering);
8365
Johan Hedbergf963e8e2012-02-20 23:30:44 +02008366 memset(&ev, 0, sizeof(ev));
8367 ev.type = hdev->discovery.type;
8368 ev.discovering = discovering;
8369
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07008370 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04008371}
Antti Julku5e762442011-08-25 16:48:02 +03008372
Marcel Holtmann1904a852015-01-11 13:50:44 -08008373static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07008374{
8375 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07008376}
8377
8378void mgmt_reenable_advertising(struct hci_dev *hdev)
8379{
8380 struct hci_request req;
8381
Arman Uguray24b4f382015-03-23 15:57:12 -07008382 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
8383 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
Marcel Holtmann5976e602013-10-06 04:08:14 -07008384 return;
8385
8386 hci_req_init(&req, hdev);
8387 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03008388 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07008389}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008390
8391static struct hci_mgmt_chan chan = {
8392 .channel = HCI_CHANNEL_CONTROL,
8393 .handler_count = ARRAY_SIZE(mgmt_handlers),
8394 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02008395 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02008396};
8397
8398int mgmt_init(void)
8399{
8400 return hci_mgmt_chan_register(&chan);
8401}
8402
8403void mgmt_exit(void)
8404{
8405 hci_mgmt_chan_unregister(&chan);
8406}