blob: 001a29a320e6db3a9026b9ec8a09f4da7511484e [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Johan Hedbergdc4270c2015-11-23 15:07:51 +020041#define MGMT_REVISION 11
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
108static const u16 mgmt_events[] = {
109 MGMT_EV_CONTROLLER_ERROR,
110 MGMT_EV_INDEX_ADDED,
111 MGMT_EV_INDEX_REMOVED,
112 MGMT_EV_NEW_SETTINGS,
113 MGMT_EV_CLASS_OF_DEV_CHANGED,
114 MGMT_EV_LOCAL_NAME_CHANGED,
115 MGMT_EV_NEW_LINK_KEY,
116 MGMT_EV_NEW_LONG_TERM_KEY,
117 MGMT_EV_DEVICE_CONNECTED,
118 MGMT_EV_DEVICE_DISCONNECTED,
119 MGMT_EV_CONNECT_FAILED,
120 MGMT_EV_PIN_CODE_REQUEST,
121 MGMT_EV_USER_CONFIRM_REQUEST,
122 MGMT_EV_USER_PASSKEY_REQUEST,
123 MGMT_EV_AUTH_FAILED,
124 MGMT_EV_DEVICE_FOUND,
125 MGMT_EV_DISCOVERING,
126 MGMT_EV_DEVICE_BLOCKED,
127 MGMT_EV_DEVICE_UNBLOCKED,
128 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300129 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800130 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700131 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200132 MGMT_EV_DEVICE_ADDED,
133 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300134 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200135 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200136 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200137 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700138 MGMT_EV_EXT_INDEX_ADDED,
139 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700140 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700141 MGMT_EV_ADVERTISING_ADDED,
142 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200143};
144
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700145static const u16 mgmt_untrusted_commands[] = {
146 MGMT_OP_READ_INDEX_LIST,
147 MGMT_OP_READ_INFO,
148 MGMT_OP_READ_UNCONF_INDEX_LIST,
149 MGMT_OP_READ_CONFIG_INFO,
150 MGMT_OP_READ_EXT_INDEX_LIST,
151};
152
153static const u16 mgmt_untrusted_events[] = {
154 MGMT_EV_INDEX_ADDED,
155 MGMT_EV_INDEX_REMOVED,
156 MGMT_EV_NEW_SETTINGS,
157 MGMT_EV_CLASS_OF_DEV_CHANGED,
158 MGMT_EV_LOCAL_NAME_CHANGED,
159 MGMT_EV_UNCONF_INDEX_ADDED,
160 MGMT_EV_UNCONF_INDEX_REMOVED,
161 MGMT_EV_NEW_CONFIG_OPTIONS,
162 MGMT_EV_EXT_INDEX_ADDED,
163 MGMT_EV_EXT_INDEX_REMOVED,
164};
165
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800166#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200167
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200168#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
169 "\x00\x00\x00\x00\x00\x00\x00\x00"
170
Johan Hedbergca69b792011-11-11 18:10:00 +0200171/* HCI to MGMT error code conversion table */
172static u8 mgmt_status_table[] = {
173 MGMT_STATUS_SUCCESS,
174 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
175 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
176 MGMT_STATUS_FAILED, /* Hardware Failure */
177 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
178 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200179 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200180 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
181 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
182 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
184 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
185 MGMT_STATUS_BUSY, /* Command Disallowed */
186 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
187 MGMT_STATUS_REJECTED, /* Rejected Security */
188 MGMT_STATUS_REJECTED, /* Rejected Personal */
189 MGMT_STATUS_TIMEOUT, /* Host Timeout */
190 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
191 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
192 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
193 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
194 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
195 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
196 MGMT_STATUS_BUSY, /* Repeated Attempts */
197 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
198 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
199 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
200 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
201 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
202 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
203 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
204 MGMT_STATUS_FAILED, /* Unspecified Error */
205 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
206 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
207 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
208 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
209 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
210 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
211 MGMT_STATUS_FAILED, /* Unit Link Key Used */
212 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
213 MGMT_STATUS_TIMEOUT, /* Instant Passed */
214 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
215 MGMT_STATUS_FAILED, /* Transaction Collision */
216 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
217 MGMT_STATUS_REJECTED, /* QoS Rejected */
218 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
219 MGMT_STATUS_REJECTED, /* Insufficient Security */
220 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
221 MGMT_STATUS_BUSY, /* Role Switch Pending */
222 MGMT_STATUS_FAILED, /* Slot Violation */
223 MGMT_STATUS_FAILED, /* Role Switch Failed */
224 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
225 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
226 MGMT_STATUS_BUSY, /* Host Busy Pairing */
227 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
228 MGMT_STATUS_BUSY, /* Controller Busy */
229 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
230 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
231 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
232 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
233 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
234};
235
236static u8 mgmt_status(u8 hci_status)
237{
238 if (hci_status < ARRAY_SIZE(mgmt_status_table))
239 return mgmt_status_table[hci_status];
240
241 return MGMT_STATUS_FAILED;
242}
243
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700244static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
245 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700246{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700247 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
248 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700249}
250
Marcel Holtmann72000df2015-03-16 16:11:21 -0700251static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
252 u16 len, int flag, struct sock *skip_sk)
253{
254 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
255 flag, skip_sk);
256}
257
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700258static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
259 u16 len, struct sock *skip_sk)
260{
261 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
262 HCI_MGMT_GENERIC_EVENTS, skip_sk);
263}
264
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200265static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
266 struct sock *skip_sk)
267{
268 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700269 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200270}
271
Johan Hedberg85813a72015-10-21 18:02:59 +0300272static u8 le_addr_type(u8 mgmt_addr_type)
273{
274 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
275 return ADDR_LE_DEV_PUBLIC;
276 else
277 return ADDR_LE_DEV_RANDOM;
278}
279
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300280static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
281 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200282{
283 struct mgmt_rp_read_version rp;
284
285 BT_DBG("sock %p", sk);
286
287 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700288 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200289
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200290 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
291 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200292}
293
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300294static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
295 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296{
297 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700298 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200299 size_t rp_size;
300 int i, err;
301
302 BT_DBG("sock %p", sk);
303
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700304 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
305 num_commands = ARRAY_SIZE(mgmt_commands);
306 num_events = ARRAY_SIZE(mgmt_events);
307 } else {
308 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
309 num_events = ARRAY_SIZE(mgmt_untrusted_events);
310 }
311
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
313
314 rp = kmalloc(rp_size, GFP_KERNEL);
315 if (!rp)
316 return -ENOMEM;
317
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700318 rp->num_commands = cpu_to_le16(num_commands);
319 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200320
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700321 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
322 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200323
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700324 for (i = 0; i < num_commands; i++, opcode++)
325 put_unaligned_le16(mgmt_commands[i], opcode);
326
327 for (i = 0; i < num_events; i++, opcode++)
328 put_unaligned_le16(mgmt_events[i], opcode);
329 } else {
330 __le16 *opcode = rp->opcodes;
331
332 for (i = 0; i < num_commands; i++, opcode++)
333 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
334
335 for (i = 0; i < num_events; i++, opcode++)
336 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
337 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200338
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200339 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
340 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200341 kfree(rp);
342
343 return err;
344}
345
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300346static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
347 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200351 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
355 BT_DBG("sock %p", sk);
356
357 read_lock(&hci_dev_list_lock);
358
359 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300360 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200361 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700362 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700363 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364 }
365
Johan Hedberga38528f2011-01-22 06:46:43 +0200366 rp_len = sizeof(*rp) + (2 * count);
367 rp = kmalloc(rp_len, GFP_ATOMIC);
368 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100369 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200370 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100371 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372
Johan Hedberg476e44c2012-10-19 20:10:46 +0300373 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200374 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700375 if (hci_dev_test_flag(d, HCI_SETUP) ||
376 hci_dev_test_flag(d, HCI_CONFIG) ||
377 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200378 continue;
379
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200380 /* Devices marked as raw-only are neither configured
381 * nor unconfigured controllers.
382 */
383 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700384 continue;
385
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700387 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700388 rp->index[count++] = cpu_to_le16(d->id);
389 BT_DBG("Added hci%u", d->id);
390 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200391 }
392
Johan Hedberg476e44c2012-10-19 20:10:46 +0300393 rp->num_controllers = cpu_to_le16(count);
394 rp_len = sizeof(*rp) + (2 * count);
395
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 read_unlock(&hci_dev_list_lock);
397
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200398 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
399 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400
Johan Hedberga38528f2011-01-22 06:46:43 +0200401 kfree(rp);
402
403 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200404}
405
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200406static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
407 void *data, u16 data_len)
408{
409 struct mgmt_rp_read_unconf_index_list *rp;
410 struct hci_dev *d;
411 size_t rp_len;
412 u16 count;
413 int err;
414
415 BT_DBG("sock %p", sk);
416
417 read_lock(&hci_dev_list_lock);
418
419 count = 0;
420 list_for_each_entry(d, &hci_dev_list, list) {
421 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700422 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200423 count++;
424 }
425
426 rp_len = sizeof(*rp) + (2 * count);
427 rp = kmalloc(rp_len, GFP_ATOMIC);
428 if (!rp) {
429 read_unlock(&hci_dev_list_lock);
430 return -ENOMEM;
431 }
432
433 count = 0;
434 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700435 if (hci_dev_test_flag(d, HCI_SETUP) ||
436 hci_dev_test_flag(d, HCI_CONFIG) ||
437 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200438 continue;
439
440 /* Devices marked as raw-only are neither configured
441 * nor unconfigured controllers.
442 */
443 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
444 continue;
445
446 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700447 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200448 rp->index[count++] = cpu_to_le16(d->id);
449 BT_DBG("Added hci%u", d->id);
450 }
451 }
452
453 rp->num_controllers = cpu_to_le16(count);
454 rp_len = sizeof(*rp) + (2 * count);
455
456 read_unlock(&hci_dev_list_lock);
457
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200458 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
459 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200460
461 kfree(rp);
462
463 return err;
464}
465
Marcel Holtmann96f14742015-03-14 19:27:57 -0700466static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
467 void *data, u16 data_len)
468{
469 struct mgmt_rp_read_ext_index_list *rp;
470 struct hci_dev *d;
471 size_t rp_len;
472 u16 count;
473 int err;
474
475 BT_DBG("sock %p", sk);
476
477 read_lock(&hci_dev_list_lock);
478
479 count = 0;
480 list_for_each_entry(d, &hci_dev_list, list) {
481 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
482 count++;
483 }
484
485 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
486 rp = kmalloc(rp_len, GFP_ATOMIC);
487 if (!rp) {
488 read_unlock(&hci_dev_list_lock);
489 return -ENOMEM;
490 }
491
492 count = 0;
493 list_for_each_entry(d, &hci_dev_list, list) {
494 if (hci_dev_test_flag(d, HCI_SETUP) ||
495 hci_dev_test_flag(d, HCI_CONFIG) ||
496 hci_dev_test_flag(d, HCI_USER_CHANNEL))
497 continue;
498
499 /* Devices marked as raw-only are neither configured
500 * nor unconfigured controllers.
501 */
502 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
503 continue;
504
505 if (d->dev_type == HCI_BREDR) {
506 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
507 rp->entry[count].type = 0x01;
508 else
509 rp->entry[count].type = 0x00;
510 } else if (d->dev_type == HCI_AMP) {
511 rp->entry[count].type = 0x02;
512 } else {
513 continue;
514 }
515
516 rp->entry[count].bus = d->bus;
517 rp->entry[count++].index = cpu_to_le16(d->id);
518 BT_DBG("Added hci%u", d->id);
519 }
520
521 rp->num_controllers = cpu_to_le16(count);
522 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
523
524 read_unlock(&hci_dev_list_lock);
525
526 /* If this command is called at least once, then all the
527 * default index and unconfigured index events are disabled
528 * and from now on only extended index events are used.
529 */
530 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
531 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
532 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
533
534 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
535 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
536
537 kfree(rp);
538
539 return err;
540}
541
Marcel Holtmanndbece372014-07-04 18:11:55 +0200542static bool is_configured(struct hci_dev *hdev)
543{
544 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700545 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200546 return false;
547
548 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
549 !bacmp(&hdev->public_addr, BDADDR_ANY))
550 return false;
551
552 return true;
553}
554
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200555static __le32 get_missing_options(struct hci_dev *hdev)
556{
557 u32 options = 0;
558
Marcel Holtmanndbece372014-07-04 18:11:55 +0200559 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700560 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200561 options |= MGMT_OPTION_EXTERNAL_CONFIG;
562
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200563 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
564 !bacmp(&hdev->public_addr, BDADDR_ANY))
565 options |= MGMT_OPTION_PUBLIC_ADDRESS;
566
567 return cpu_to_le32(options);
568}
569
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200570static int new_options(struct hci_dev *hdev, struct sock *skip)
571{
572 __le32 options = get_missing_options(hdev);
573
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700574 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
575 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200576}
577
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
579{
580 __le32 options = get_missing_options(hdev);
581
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200582 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
583 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200584}
585
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200586static int read_config_info(struct sock *sk, struct hci_dev *hdev,
587 void *data, u16 data_len)
588{
589 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200590 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591
592 BT_DBG("sock %p %s", sk, hdev->name);
593
594 hci_dev_lock(hdev);
595
596 memset(&rp, 0, sizeof(rp));
597 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200598
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
600 options |= MGMT_OPTION_EXTERNAL_CONFIG;
601
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200602 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603 options |= MGMT_OPTION_PUBLIC_ADDRESS;
604
605 rp.supported_options = cpu_to_le32(options);
606 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607
608 hci_dev_unlock(hdev);
609
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
611 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612}
613
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200614static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200615{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200617
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300619 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800620 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300621 settings |= MGMT_SETTING_CONNECTABLE;
622 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Andre Guedesed3fa312012-07-24 15:03:46 -0300624 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500625 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
626 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627 settings |= MGMT_SETTING_BREDR;
628 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700629
630 if (lmp_ssp_capable(hdev)) {
631 settings |= MGMT_SETTING_SSP;
632 settings |= MGMT_SETTING_HS;
633 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800634
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800635 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800636 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700637 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100638
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300639 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200640 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300641 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300642 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200643 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800644 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300645 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200646
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200647 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
648 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200649 settings |= MGMT_SETTING_CONFIGURATION;
650
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651 return settings;
652}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200653
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200654static u32 get_current_settings(struct hci_dev *hdev)
655{
656 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200657
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200658 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100659 settings |= MGMT_SETTING_POWERED;
660
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662 settings |= MGMT_SETTING_CONNECTABLE;
663
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700664 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500665 settings |= MGMT_SETTING_FAST_CONNECTABLE;
666
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700667 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200668 settings |= MGMT_SETTING_DISCOVERABLE;
669
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700670 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300671 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700673 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674 settings |= MGMT_SETTING_BREDR;
675
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700676 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700679 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200681
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700682 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200683 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700685 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200686 settings |= MGMT_SETTING_HS;
687
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700688 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300689 settings |= MGMT_SETTING_ADVERTISING;
690
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700691 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800692 settings |= MGMT_SETTING_SECURE_CONN;
693
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700694 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800695 settings |= MGMT_SETTING_DEBUG_KEYS;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200698 settings |= MGMT_SETTING_PRIVACY;
699
Marcel Holtmann93690c22015-03-06 10:11:21 -0800700 /* The current setting for static address has two purposes. The
701 * first is to indicate if the static address will be used and
702 * the second is to indicate if it is actually set.
703 *
704 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700705 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800706 * address is actually used decides if the flag is set or not.
707 *
708 * For single mode LE only controllers and dual-mode controllers
709 * with BR/EDR disabled, the existence of the static address will
710 * be evaluated.
711 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700712 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700713 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800714 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
715 if (bacmp(&hdev->static_addr, BDADDR_ANY))
716 settings |= MGMT_SETTING_STATIC_ADDRESS;
717 }
718
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200720}
721
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300722#define PNP_INFO_SVCLASS_ID 0x1200
723
Johan Hedberg213202e2013-01-27 00:31:33 +0200724static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
725{
726 u8 *ptr = data, *uuids_start = NULL;
727 struct bt_uuid *uuid;
728
729 if (len < 4)
730 return ptr;
731
732 list_for_each_entry(uuid, &hdev->uuids, list) {
733 u16 uuid16;
734
735 if (uuid->size != 16)
736 continue;
737
738 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
739 if (uuid16 < 0x1100)
740 continue;
741
742 if (uuid16 == PNP_INFO_SVCLASS_ID)
743 continue;
744
745 if (!uuids_start) {
746 uuids_start = ptr;
747 uuids_start[0] = 1;
748 uuids_start[1] = EIR_UUID16_ALL;
749 ptr += 2;
750 }
751
752 /* Stop if not enough space to put next UUID */
753 if ((ptr - data) + sizeof(u16) > len) {
754 uuids_start[1] = EIR_UUID16_SOME;
755 break;
756 }
757
758 *ptr++ = (uuid16 & 0x00ff);
759 *ptr++ = (uuid16 & 0xff00) >> 8;
760 uuids_start[0] += sizeof(uuid16);
761 }
762
763 return ptr;
764}
765
Johan Hedbergcdf19632013-01-27 00:31:34 +0200766static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
767{
768 u8 *ptr = data, *uuids_start = NULL;
769 struct bt_uuid *uuid;
770
771 if (len < 6)
772 return ptr;
773
774 list_for_each_entry(uuid, &hdev->uuids, list) {
775 if (uuid->size != 32)
776 continue;
777
778 if (!uuids_start) {
779 uuids_start = ptr;
780 uuids_start[0] = 1;
781 uuids_start[1] = EIR_UUID32_ALL;
782 ptr += 2;
783 }
784
785 /* Stop if not enough space to put next UUID */
786 if ((ptr - data) + sizeof(u32) > len) {
787 uuids_start[1] = EIR_UUID32_SOME;
788 break;
789 }
790
791 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
792 ptr += sizeof(u32);
793 uuids_start[0] += sizeof(u32);
794 }
795
796 return ptr;
797}
798
Johan Hedbergc00d5752013-01-27 00:31:35 +0200799static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
800{
801 u8 *ptr = data, *uuids_start = NULL;
802 struct bt_uuid *uuid;
803
804 if (len < 18)
805 return ptr;
806
807 list_for_each_entry(uuid, &hdev->uuids, list) {
808 if (uuid->size != 128)
809 continue;
810
811 if (!uuids_start) {
812 uuids_start = ptr;
813 uuids_start[0] = 1;
814 uuids_start[1] = EIR_UUID128_ALL;
815 ptr += 2;
816 }
817
818 /* Stop if not enough space to put next UUID */
819 if ((ptr - data) + 16 > len) {
820 uuids_start[1] = EIR_UUID128_SOME;
821 break;
822 }
823
824 memcpy(ptr, uuid->uuid, 16);
825 ptr += 16;
826 uuids_start[0] += 16;
827 }
828
829 return ptr;
830}
831
Johan Hedberg333ae952015-03-17 13:48:47 +0200832static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
833{
834 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
835}
836
Johan Hedberg333ae952015-03-17 13:48:47 +0200837static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
838 struct hci_dev *hdev,
839 const void *data)
840{
841 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
842}
843
Johan Hedbergf2252572015-11-18 12:49:20 +0200844u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300845{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200846 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300847
848 /* If there's a pending mgmt command the flags will not yet have
849 * their final values, so check for this first.
850 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200851 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300852 if (cmd) {
853 struct mgmt_mode *cp = cmd->param;
854 if (cp->val == 0x01)
855 return LE_AD_GENERAL;
856 else if (cp->val == 0x02)
857 return LE_AD_LIMITED;
858 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700859 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300860 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700861 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300862 return LE_AD_GENERAL;
863 }
864
865 return 0;
866}
867
Johan Hedbergf2252572015-11-18 12:49:20 +0200868bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700869{
870 struct mgmt_pending_cmd *cmd;
871
872 /* If there's a pending mgmt command the flag will not yet have
873 * it's final value, so check for this first.
874 */
875 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
876 if (cmd) {
877 struct mgmt_mode *cp = cmd->param;
878
879 return cp->val;
880 }
881
882 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
883}
884
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300885static void create_eir(struct hci_dev *hdev, u8 *data)
886{
887 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300888 size_t name_len;
889
890 name_len = strlen(hdev->dev_name);
891
892 if (name_len > 0) {
893 /* EIR Data type */
894 if (name_len > 48) {
895 name_len = 48;
896 ptr[1] = EIR_NAME_SHORT;
897 } else
898 ptr[1] = EIR_NAME_COMPLETE;
899
900 /* EIR Data length */
901 ptr[0] = name_len + 1;
902
903 memcpy(ptr + 2, hdev->dev_name, name_len);
904
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300905 ptr += (name_len + 2);
906 }
907
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100908 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700909 ptr[0] = 2;
910 ptr[1] = EIR_TX_POWER;
911 ptr[2] = (u8) hdev->inq_tx_power;
912
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700913 ptr += 3;
914 }
915
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700916 if (hdev->devid_source > 0) {
917 ptr[0] = 9;
918 ptr[1] = EIR_DEVICE_ID;
919
920 put_unaligned_le16(hdev->devid_source, ptr + 2);
921 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
922 put_unaligned_le16(hdev->devid_product, ptr + 6);
923 put_unaligned_le16(hdev->devid_version, ptr + 8);
924
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700925 ptr += 10;
926 }
927
Johan Hedberg213202e2013-01-27 00:31:33 +0200928 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200929 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200930 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300931}
932
Johan Hedberg890ea892013-03-15 17:06:52 -0500933static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300934{
Johan Hedberg890ea892013-03-15 17:06:52 -0500935 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300936 struct hci_cp_write_eir cp;
937
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200938 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500939 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200940
Johan Hedberg976eb202012-10-24 21:12:01 +0300941 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500942 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300943
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700944 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -0500945 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300946
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700947 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -0500948 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300949
950 memset(&cp, 0, sizeof(cp));
951
952 create_eir(hdev, cp.data);
953
954 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500955 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300956
957 memcpy(hdev->eir, cp.data, sizeof(cp.data));
958
Johan Hedberg890ea892013-03-15 17:06:52 -0500959 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300960}
961
Johan Hedberg7d785252011-12-15 00:47:39 +0200962static void service_cache_off(struct work_struct *work)
963{
964 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300965 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500966 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200967
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700968 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200969 return;
970
Johan Hedberg890ea892013-03-15 17:06:52 -0500971 hci_req_init(&req, hdev);
972
Johan Hedberg7d785252011-12-15 00:47:39 +0200973 hci_dev_lock(hdev);
974
Johan Hedberg890ea892013-03-15 17:06:52 -0500975 update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200976 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200977
978 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500979
980 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200981}
982
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200983static void rpa_expired(struct work_struct *work)
984{
985 struct hci_dev *hdev = container_of(work, struct hci_dev,
986 rpa_expired.work);
987 struct hci_request req;
988
989 BT_DBG("");
990
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700991 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200992
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700993 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200994 return;
995
996 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200997 * controller happens in the hci_req_enable_advertising()
998 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200999 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001000 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001001 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001002 hci_req_run(&req, NULL);
1003}
1004
Johan Hedberg6a919082012-02-28 06:17:26 +02001005static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001006{
Marcel Holtmann238be782015-03-13 02:11:06 -07001007 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001008 return;
1009
Johan Hedberg4f87da82012-03-02 19:55:56 +02001010 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001011 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001012
Johan Hedberg4f87da82012-03-02 19:55:56 +02001013 /* Non-mgmt controlled devices get this bit set
1014 * implicitly so that pairing works for them, however
1015 * for mgmt we require user-space to explicitly enable
1016 * it
1017 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001018 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001019}
1020
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001021static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001022 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001023{
1024 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001026 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001029
Johan Hedberg03811012010-12-08 00:21:06 +02001030 memset(&rp, 0, sizeof(rp));
1031
Johan Hedberg03811012010-12-08 00:21:06 +02001032 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001033
1034 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001035 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001036
1037 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1038 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1039
1040 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001041
1042 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001043 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001044
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001046
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001047 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1048 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001049}
1050
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001051static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001052{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001053 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001054
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001055 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1056 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001057}
1058
Marcel Holtmann1904a852015-01-11 13:50:44 -08001059static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001060{
1061 BT_DBG("%s status 0x%02x", hdev->name, status);
1062
Johan Hedberga3172b72014-02-28 09:33:44 +02001063 if (hci_conn_count(hdev) == 0) {
1064 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001065 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001066 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001067}
1068
Johan Hedbergf2252572015-11-18 12:49:20 +02001069void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001070{
1071 struct mgmt_ev_advertising_added ev;
1072
1073 ev.instance = instance;
1074
1075 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1076}
1077
Johan Hedbergf2252572015-11-18 12:49:20 +02001078void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
1079 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -07001080{
1081 struct mgmt_ev_advertising_removed ev;
1082
1083 ev.instance = instance;
1084
1085 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1086}
1087
Florian Grandel7816b822015-06-18 03:16:45 +02001088static void cancel_adv_timeout(struct hci_dev *hdev)
1089{
1090 if (hdev->adv_instance_timeout) {
1091 hdev->adv_instance_timeout = 0;
1092 cancel_delayed_work(&hdev->adv_instance_expire);
1093 }
1094}
1095
Johan Hedberg8b064a32014-02-24 14:52:22 +02001096static int clean_up_hci_state(struct hci_dev *hdev)
1097{
1098 struct hci_request req;
1099 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001100 bool discov_stopped;
1101 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001102
1103 hci_req_init(&req, hdev);
1104
1105 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1106 test_bit(HCI_PSCAN, &hdev->flags)) {
1107 u8 scan = 0x00;
1108 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1109 }
1110
Johan Hedbergf2252572015-11-18 12:49:20 +02001111 hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001112
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001113 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001114 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001115
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001116 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001117
1118 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001119 /* 0x15 == Terminated due to Power Off */
1120 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001121 }
1122
Johan Hedberg23a48092014-07-08 16:05:06 +03001123 err = hci_req_run(&req, clean_up_hci_complete);
1124 if (!err && discov_stopped)
1125 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1126
1127 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001128}
1129
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001130static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001131 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001132{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001133 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001134 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001135 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001137 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001138
Johan Hedberga7e80f22013-01-09 16:05:19 +02001139 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001140 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1141 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001143 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001144
Johan Hedberg333ae952015-03-17 13:48:47 +02001145 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001146 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1147 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001148 goto failed;
1149 }
1150
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001151 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001152 cancel_delayed_work(&hdev->power_off);
1153
1154 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001155 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1156 data, len);
1157 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001158 goto failed;
1159 }
1160 }
1161
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001162 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001163 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001164 goto failed;
1165 }
1166
Johan Hedberg03811012010-12-08 00:21:06 +02001167 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1168 if (!cmd) {
1169 err = -ENOMEM;
1170 goto failed;
1171 }
1172
Johan Hedberg8b064a32014-02-24 14:52:22 +02001173 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001174 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001175 err = 0;
1176 } else {
1177 /* Disconnect connections, stop scans, etc */
1178 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001179 if (!err)
1180 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1181 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001182
Johan Hedberg8b064a32014-02-24 14:52:22 +02001183 /* ENODATA means there were no HCI commands queued */
1184 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001185 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001186 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1187 err = 0;
1188 }
1189 }
Johan Hedberg03811012010-12-08 00:21:06 +02001190
Johan Hedberge41d8b42010-12-13 21:07:03 +02001191failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001192 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001193 return err;
1194}
1195
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001196static int new_settings(struct hci_dev *hdev, struct sock *skip)
1197{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001198 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001199
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001200 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1201 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001202}
1203
Johan Hedberg91a668b2014-07-09 13:28:26 +03001204int mgmt_new_settings(struct hci_dev *hdev)
1205{
1206 return new_settings(hdev, NULL);
1207}
1208
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001209struct cmd_lookup {
1210 struct sock *sk;
1211 struct hci_dev *hdev;
1212 u8 mgmt_status;
1213};
1214
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001215static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001216{
1217 struct cmd_lookup *match = data;
1218
1219 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1220
1221 list_del(&cmd->list);
1222
1223 if (match->sk == NULL) {
1224 match->sk = cmd->sk;
1225 sock_hold(match->sk);
1226 }
1227
1228 mgmt_pending_free(cmd);
1229}
1230
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001231static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001232{
1233 u8 *status = data;
1234
Johan Hedberga69e8372015-03-06 21:08:53 +02001235 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001236 mgmt_pending_remove(cmd);
1237}
1238
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001239static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001240{
1241 if (cmd->cmd_complete) {
1242 u8 *status = data;
1243
1244 cmd->cmd_complete(cmd, *status);
1245 mgmt_pending_remove(cmd);
1246
1247 return;
1248 }
1249
1250 cmd_status_rsp(cmd, data);
1251}
1252
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001253static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001254{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001255 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1256 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001257}
1258
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001259static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001260{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001261 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1262 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001263}
1264
Johan Hedberge6fe7982013-10-02 15:45:22 +03001265static u8 mgmt_bredr_support(struct hci_dev *hdev)
1266{
1267 if (!lmp_bredr_capable(hdev))
1268 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001269 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001270 return MGMT_STATUS_REJECTED;
1271 else
1272 return MGMT_STATUS_SUCCESS;
1273}
1274
1275static u8 mgmt_le_support(struct hci_dev *hdev)
1276{
1277 if (!lmp_le_capable(hdev))
1278 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001279 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001280 return MGMT_STATUS_REJECTED;
1281 else
1282 return MGMT_STATUS_SUCCESS;
1283}
1284
Johan Hedbergaed1a882015-11-22 17:24:44 +03001285void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001286{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001287 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001288
1289 BT_DBG("status 0x%02x", status);
1290
1291 hci_dev_lock(hdev);
1292
Johan Hedberg333ae952015-03-17 13:48:47 +02001293 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001294 if (!cmd)
1295 goto unlock;
1296
1297 if (status) {
1298 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001299 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001300 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001301 goto remove_cmd;
1302 }
1303
Johan Hedbergaed1a882015-11-22 17:24:44 +03001304 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1305 hdev->discov_timeout > 0) {
1306 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1307 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001308 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001309
1310 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001311 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001312
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001313remove_cmd:
1314 mgmt_pending_remove(cmd);
1315
1316unlock:
1317 hci_dev_unlock(hdev);
1318}
1319
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001320static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001321 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001322{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001323 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001324 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001325 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001326 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328 BT_DBG("request for %s", hdev->name);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001329
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001330 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1331 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001332 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1333 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001334
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001335 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001336 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1337 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001338
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001339 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001340
1341 /* Disabling discoverable requires that no timeout is set,
1342 * and enabling limited discoverable requires a timeout.
1343 */
1344 if ((cp->val == 0x00 && timeout > 0) ||
1345 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001346 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1347 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001348
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001349 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001350
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001351 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001352 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1353 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001354 goto failed;
1355 }
1356
Johan Hedberg333ae952015-03-17 13:48:47 +02001357 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1358 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001359 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1360 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001361 goto failed;
1362 }
1363
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001364 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001365 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1366 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001367 goto failed;
1368 }
1369
1370 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001371 bool changed = false;
1372
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001373 /* Setting limited discoverable when powered off is
1374 * not a valid operation since it requires a timeout
1375 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1376 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001377 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001378 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001379 changed = true;
1380 }
1381
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001382 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001383 if (err < 0)
1384 goto failed;
1385
1386 if (changed)
1387 err = new_settings(hdev, sk);
1388
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001389 goto failed;
1390 }
1391
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001392 /* If the current mode is the same, then just update the timeout
1393 * value with the new value. And if only the timeout gets updated,
1394 * then no need for any HCI transactions.
1395 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001396 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1397 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1398 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001399 cancel_delayed_work(&hdev->discov_off);
1400 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001401
Marcel Holtmann36261542013-10-15 08:28:51 -07001402 if (cp->val && hdev->discov_timeout > 0) {
1403 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001404 queue_delayed_work(hdev->req_workqueue,
1405 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001406 }
1407
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001408 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001409 goto failed;
1410 }
1411
1412 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1413 if (!cmd) {
1414 err = -ENOMEM;
1415 goto failed;
1416 }
1417
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001418 /* Cancel any potential discoverable timeout that might be
1419 * still active and store new timeout value. The arming of
1420 * the timeout happens in the complete handler.
1421 */
1422 cancel_delayed_work(&hdev->discov_off);
1423 hdev->discov_timeout = timeout;
1424
Johan Hedbergaed1a882015-11-22 17:24:44 +03001425 if (cp->val)
1426 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1427 else
1428 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1429
Johan Hedbergb456f872013-10-19 23:38:22 +03001430 /* Limited discoverable mode */
1431 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001432 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001433 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001434 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001435
Johan Hedbergaed1a882015-11-22 17:24:44 +03001436 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1437 err = 0;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001438
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001439failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001440 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001441 return err;
1442}
1443
Johan Hedberg406d7802013-03-15 17:07:09 -05001444static void write_fast_connectable(struct hci_request *req, bool enable)
1445{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001446 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001447 struct hci_cp_write_page_scan_activity acp;
1448 u8 type;
1449
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001450 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001451 return;
1452
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001453 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1454 return;
1455
Johan Hedberg406d7802013-03-15 17:07:09 -05001456 if (enable) {
1457 type = PAGE_SCAN_TYPE_INTERLACED;
1458
1459 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001460 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001461 } else {
1462 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1463
1464 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001465 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001466 }
1467
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001468 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001469
Johan Hedbergbd98b992013-03-15 17:07:13 -05001470 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1471 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1472 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1473 sizeof(acp), &acp);
1474
1475 if (hdev->page_scan_type != type)
1476 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001477}
1478
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001479void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001480{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001481 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001482
1483 BT_DBG("status 0x%02x", status);
1484
1485 hci_dev_lock(hdev);
1486
Johan Hedberg333ae952015-03-17 13:48:47 +02001487 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001488 if (!cmd)
1489 goto unlock;
1490
Johan Hedberg37438c12013-10-14 16:20:05 +03001491 if (status) {
1492 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001493 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001494 goto remove_cmd;
1495 }
1496
Johan Hedberg2b76f452013-03-15 17:07:04 -05001497 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001498 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001499
Johan Hedberg37438c12013-10-14 16:20:05 +03001500remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001501 mgmt_pending_remove(cmd);
1502
1503unlock:
1504 hci_dev_unlock(hdev);
1505}
1506
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001507static int set_connectable_update_settings(struct hci_dev *hdev,
1508 struct sock *sk, u8 val)
1509{
1510 bool changed = false;
1511 int err;
1512
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001513 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001514 changed = true;
1515
1516 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001517 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001518 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001519 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1520 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001521 }
1522
1523 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1524 if (err < 0)
1525 return err;
1526
Johan Hedberg562064e2014-07-08 16:35:34 +03001527 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001528 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001529 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001530 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001531 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001532
1533 return 0;
1534}
1535
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001536static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001537 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001538{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001539 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001540 struct mgmt_pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001541 int err;
1542
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001544
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001545 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1546 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001547 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1548 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001549
Johan Hedberga7e80f22013-01-09 16:05:19 +02001550 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001551 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1552 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001553
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001554 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001555
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001556 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001557 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001558 goto failed;
1559 }
1560
Johan Hedberg333ae952015-03-17 13:48:47 +02001561 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1562 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001563 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1564 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565 goto failed;
1566 }
1567
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1569 if (!cmd) {
1570 err = -ENOMEM;
1571 goto failed;
1572 }
1573
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001574 if (cp->val) {
1575 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1576 } else {
1577 if (hdev->discov_timeout > 0)
1578 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001579
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001580 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1581 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1582 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001583 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001584
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001585 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1586 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001587
1588failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001589 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001590 return err;
1591}
1592
Johan Hedbergb2939472014-07-30 09:22:23 +03001593static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001594 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001595{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001596 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001597 bool changed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001598 int err;
1599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001600 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001601
Johan Hedberga7e80f22013-01-09 16:05:19 +02001602 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001603 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1604 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001605
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001606 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001607
1608 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001609 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001610 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001611 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001612
Johan Hedbergb2939472014-07-30 09:22:23 +03001613 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001614 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001615 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001616
Marcel Holtmann55594352013-10-06 16:11:57 -07001617 if (changed)
1618 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001619
Marcel Holtmann55594352013-10-06 16:11:57 -07001620unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001621 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001622 return err;
1623}
1624
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001625static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1626 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001627{
1628 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001629 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001630 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001631 int err;
1632
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001633 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001634
Johan Hedberge6fe7982013-10-02 15:45:22 +03001635 status = mgmt_bredr_support(hdev);
1636 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001637 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1638 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001639
Johan Hedberga7e80f22013-01-09 16:05:19 +02001640 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001641 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1642 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001643
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001644 hci_dev_lock(hdev);
1645
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001646 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001647 bool changed = false;
1648
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001649 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001650 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001651 changed = true;
1652 }
1653
1654 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1655 if (err < 0)
1656 goto failed;
1657
1658 if (changed)
1659 err = new_settings(hdev, sk);
1660
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001661 goto failed;
1662 }
1663
Johan Hedberg333ae952015-03-17 13:48:47 +02001664 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001665 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1666 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001667 goto failed;
1668 }
1669
1670 val = !!cp->val;
1671
1672 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1673 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1674 goto failed;
1675 }
1676
1677 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1678 if (!cmd) {
1679 err = -ENOMEM;
1680 goto failed;
1681 }
1682
1683 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1684 if (err < 0) {
1685 mgmt_pending_remove(cmd);
1686 goto failed;
1687 }
1688
1689failed:
1690 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001691 return err;
1692}
1693
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001694static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001695{
1696 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001697 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001698 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001699 int err;
1700
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001701 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001702
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001703 status = mgmt_bredr_support(hdev);
1704 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001705 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001706
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001707 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001708 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1709 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001710
Johan Hedberga7e80f22013-01-09 16:05:19 +02001711 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001712 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1713 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001714
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001715 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001716
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001717 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001718 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001719
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001720 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001721 changed = !hci_dev_test_and_set_flag(hdev,
1722 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001723 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001724 changed = hci_dev_test_and_clear_flag(hdev,
1725 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001726 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001727 changed = hci_dev_test_and_clear_flag(hdev,
1728 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001729 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001730 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001731 }
1732
1733 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1734 if (err < 0)
1735 goto failed;
1736
1737 if (changed)
1738 err = new_settings(hdev, sk);
1739
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001740 goto failed;
1741 }
1742
Johan Hedberg333ae952015-03-17 13:48:47 +02001743 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001744 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1745 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001746 goto failed;
1747 }
1748
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001749 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001750 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1751 goto failed;
1752 }
1753
1754 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1755 if (!cmd) {
1756 err = -ENOMEM;
1757 goto failed;
1758 }
1759
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001760 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001761 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1762 sizeof(cp->val), &cp->val);
1763
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001764 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001765 if (err < 0) {
1766 mgmt_pending_remove(cmd);
1767 goto failed;
1768 }
1769
1770failed:
1771 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001772 return err;
1773}
1774
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001775static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001776{
1777 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001778 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001779 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001780 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001781
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001782 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001783
Johan Hedberge6fe7982013-10-02 15:45:22 +03001784 status = mgmt_bredr_support(hdev);
1785 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001786 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001787
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001788 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001789 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1790 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001791
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001792 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001793 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1794 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001795
Johan Hedberga7e80f22013-01-09 16:05:19 +02001796 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001797 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1798 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001799
Marcel Holtmannee392692013-10-01 22:59:23 -07001800 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001801
Johan Hedberg333ae952015-03-17 13:48:47 +02001802 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001803 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1804 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001805 goto unlock;
1806 }
1807
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001808 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001809 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001810 } else {
1811 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001812 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1813 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001814 goto unlock;
1815 }
1816
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001817 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001818 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001819
1820 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1821 if (err < 0)
1822 goto unlock;
1823
1824 if (changed)
1825 err = new_settings(hdev, sk);
1826
1827unlock:
1828 hci_dev_unlock(hdev);
1829 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001830}
1831
Marcel Holtmann1904a852015-01-11 13:50:44 -08001832static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001833{
1834 struct cmd_lookup match = { NULL, hdev };
1835
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301836 hci_dev_lock(hdev);
1837
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001838 if (status) {
1839 u8 mgmt_err = mgmt_status(status);
1840
1841 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1842 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301843 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001844 }
1845
1846 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1847
1848 new_settings(hdev, match.sk);
1849
1850 if (match.sk)
1851 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001852
1853 /* Make sure the controller has a good default for
1854 * advertising data. Restrict the update to when LE
1855 * has actually been enabled. During power on, the
1856 * update in powered_update_hci will take care of it.
1857 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001858 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001859 struct hci_request req;
1860
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001861 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +02001862 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
1863 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001864 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001865 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001866 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301867
1868unlock:
1869 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001870}
1871
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001872static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001873{
1874 struct mgmt_mode *cp = data;
1875 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001876 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001877 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001878 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001879 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001880
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001882
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001883 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001884 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1885 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001886
Johan Hedberga7e80f22013-01-09 16:05:19 +02001887 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001888 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1889 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001890
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001891 /* Bluetooth single mode LE only controllers or dual-mode
1892 * controllers configured as LE only devices, do not allow
1893 * switching LE off. These have either LE enabled explicitly
1894 * or BR/EDR has been previously switched off.
1895 *
1896 * When trying to enable an already enabled LE, then gracefully
1897 * send a positive response. Trying to disable it however will
1898 * result into rejection.
1899 */
1900 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1901 if (cp->val == 0x01)
1902 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1903
Johan Hedberga69e8372015-03-06 21:08:53 +02001904 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1905 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001906 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001907
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001908 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001909
1910 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001911 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001912
Florian Grandel847818d2015-06-18 03:16:46 +02001913 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02001914 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001915
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001916 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001917 bool changed = false;
1918
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001919 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001920 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001921 changed = true;
1922 }
1923
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001924 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001925 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001926 changed = true;
1927 }
1928
Johan Hedberg06199cf2012-02-22 16:37:11 +02001929 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1930 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001931 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001932
1933 if (changed)
1934 err = new_settings(hdev, sk);
1935
Johan Hedberg1de028c2012-02-29 19:55:35 -08001936 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001937 }
1938
Johan Hedberg333ae952015-03-17 13:48:47 +02001939 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1940 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001941 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1942 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001943 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001944 }
1945
1946 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1947 if (!cmd) {
1948 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001949 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001950 }
1951
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001952 hci_req_init(&req, hdev);
1953
Johan Hedberg06199cf2012-02-22 16:37:11 +02001954 memset(&hci_cp, 0, sizeof(hci_cp));
1955
1956 if (val) {
1957 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001958 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001959 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001960 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001961 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 }
1963
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001964 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1965 &hci_cp);
1966
1967 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301968 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001969 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001970
Johan Hedberg1de028c2012-02-29 19:55:35 -08001971unlock:
1972 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001973 return err;
1974}
1975
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001976/* This is a helper function to test for pending mgmt commands that can
1977 * cause CoD or EIR HCI commands. We can only allow one such pending
1978 * mgmt command at a time since otherwise we cannot easily track what
1979 * the current values are, will be, and based on that calculate if a new
1980 * HCI command needs to be sent and if yes with what value.
1981 */
1982static bool pending_eir_or_class(struct hci_dev *hdev)
1983{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001984 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001985
1986 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1987 switch (cmd->opcode) {
1988 case MGMT_OP_ADD_UUID:
1989 case MGMT_OP_REMOVE_UUID:
1990 case MGMT_OP_SET_DEV_CLASS:
1991 case MGMT_OP_SET_POWERED:
1992 return true;
1993 }
1994 }
1995
1996 return false;
1997}
1998
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001999static const u8 bluetooth_base_uuid[] = {
2000 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2001 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2002};
2003
2004static u8 get_uuid_size(const u8 *uuid)
2005{
2006 u32 val;
2007
2008 if (memcmp(uuid, bluetooth_base_uuid, 12))
2009 return 128;
2010
2011 val = get_unaligned_le32(&uuid[12]);
2012 if (val > 0xffff)
2013 return 32;
2014
2015 return 16;
2016}
2017
Johan Hedberg92da6092013-03-15 17:06:55 -05002018static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2019{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002020 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002021
2022 hci_dev_lock(hdev);
2023
Johan Hedberg333ae952015-03-17 13:48:47 +02002024 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002025 if (!cmd)
2026 goto unlock;
2027
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002028 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2029 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002030
2031 mgmt_pending_remove(cmd);
2032
2033unlock:
2034 hci_dev_unlock(hdev);
2035}
2036
Marcel Holtmann1904a852015-01-11 13:50:44 -08002037static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002038{
2039 BT_DBG("status 0x%02x", status);
2040
2041 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2042}
2043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002045{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002046 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002047 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002048 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002049 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002050 int err;
2051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002052 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002053
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002054 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002056 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002057 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2058 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002059 goto failed;
2060 }
2061
Andre Guedes92c4c202012-06-07 19:05:44 -03002062 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063 if (!uuid) {
2064 err = -ENOMEM;
2065 goto failed;
2066 }
2067
2068 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002069 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002070 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002071
Johan Hedbergde66aa62013-01-27 00:31:27 +02002072 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002073
Johan Hedberg890ea892013-03-15 17:06:52 -05002074 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002075
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002076 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002077 update_eir(&req);
2078
Johan Hedberg92da6092013-03-15 17:06:55 -05002079 err = hci_req_run(&req, add_uuid_complete);
2080 if (err < 0) {
2081 if (err != -ENODATA)
2082 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002083
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002084 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2085 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002086 goto failed;
2087 }
2088
2089 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002090 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002091 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002092 goto failed;
2093 }
2094
2095 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002096
2097failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002098 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099 return err;
2100}
2101
Johan Hedberg24b78d02012-02-23 23:24:30 +02002102static bool enable_service_cache(struct hci_dev *hdev)
2103{
2104 if (!hdev_is_powered(hdev))
2105 return false;
2106
Marcel Holtmann238be782015-03-13 02:11:06 -07002107 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002108 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2109 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002110 return true;
2111 }
2112
2113 return false;
2114}
2115
Marcel Holtmann1904a852015-01-11 13:50:44 -08002116static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002117{
2118 BT_DBG("status 0x%02x", status);
2119
2120 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2121}
2122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002123static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002124 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002126 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002127 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002128 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05002130 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002131 int err, found;
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002136
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002137 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002138 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2139 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002140 goto unlock;
2141 }
2142
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002143 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002144 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002145
Johan Hedberg24b78d02012-02-23 23:24:30 +02002146 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002147 err = mgmt_cmd_complete(sk, hdev->id,
2148 MGMT_OP_REMOVE_UUID,
2149 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002150 goto unlock;
2151 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002152
Johan Hedberg9246a862012-02-23 21:33:16 +02002153 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002154 }
2155
2156 found = 0;
2157
Johan Hedberg056341c2013-01-27 00:31:30 +02002158 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002159 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2160 continue;
2161
2162 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002163 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164 found++;
2165 }
2166
2167 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002168 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2169 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002170 goto unlock;
2171 }
2172
Johan Hedberg9246a862012-02-23 21:33:16 +02002173update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002174 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002175
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002176 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002177 update_eir(&req);
2178
Johan Hedberg92da6092013-03-15 17:06:55 -05002179 err = hci_req_run(&req, remove_uuid_complete);
2180 if (err < 0) {
2181 if (err != -ENODATA)
2182 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002183
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002184 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2185 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002186 goto unlock;
2187 }
2188
2189 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002190 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002191 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002192 goto unlock;
2193 }
2194
2195 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002196
2197unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002198 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002199 return err;
2200}
2201
Marcel Holtmann1904a852015-01-11 13:50:44 -08002202static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002203{
2204 BT_DBG("status 0x%02x", status);
2205
2206 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2207}
2208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002213 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002214 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002215 int err;
2216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002217 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002218
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002219 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002220 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2221 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002222
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002223 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002224
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002225 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002226 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2227 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002228 goto unlock;
2229 }
2230
2231 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002234 goto unlock;
2235 }
2236
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002237 hdev->major_class = cp->major;
2238 hdev->minor_class = cp->minor;
2239
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002240 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002241 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2242 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002243 goto unlock;
2244 }
2245
Johan Hedberg890ea892013-03-15 17:06:52 -05002246 hci_req_init(&req, hdev);
2247
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002248 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002249 hci_dev_unlock(hdev);
2250 cancel_delayed_work_sync(&hdev->service_cache);
2251 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002252 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002253 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002254
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002255 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002256
Johan Hedberg92da6092013-03-15 17:06:55 -05002257 err = hci_req_run(&req, set_class_complete);
2258 if (err < 0) {
2259 if (err != -ENODATA)
2260 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002261
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002262 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2263 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002264 goto unlock;
2265 }
2266
2267 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002268 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002269 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002270 goto unlock;
2271 }
2272
2273 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002274
Johan Hedbergb5235a62012-02-21 14:32:24 +02002275unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002276 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002277 return err;
2278}
2279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002281 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002282{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002284 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2285 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002286 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002287 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002288 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002289
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002290 BT_DBG("request for %s", hdev->name);
2291
2292 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2294 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002295
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002296 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002297 if (key_count > max_key_count) {
2298 BT_ERR("load_link_keys: too big key_count value %u",
2299 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002300 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2301 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002302 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002303
Johan Hedberg86742e12011-11-07 23:13:38 +02002304 expected_len = sizeof(*cp) + key_count *
2305 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002306 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002307 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002308 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002309 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2310 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002311 }
2312
Johan Hedberg4ae143012013-01-20 14:27:13 +02002313 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2315 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002316
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002317 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002318 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002319
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002320 for (i = 0; i < key_count; i++) {
2321 struct mgmt_link_key_info *key = &cp->keys[i];
2322
Marcel Holtmann8e991132014-01-10 02:07:25 -08002323 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002324 return mgmt_cmd_status(sk, hdev->id,
2325 MGMT_OP_LOAD_LINK_KEYS,
2326 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002327 }
2328
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002329 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002330
2331 hci_link_keys_clear(hdev);
2332
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002334 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002335 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002336 changed = hci_dev_test_and_clear_flag(hdev,
2337 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002338
2339 if (changed)
2340 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002342 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002343 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344
Johan Hedberg58e92932014-06-24 14:00:26 +03002345 /* Always ignore debug keys and require a new pairing if
2346 * the user wants to use them.
2347 */
2348 if (key->type == HCI_LK_DEBUG_COMBINATION)
2349 continue;
2350
Johan Hedberg7652ff62014-06-24 13:15:49 +03002351 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2352 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353 }
2354
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002355 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002357 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002359 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360}
2361
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002362static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002364{
2365 struct mgmt_ev_device_unpaired ev;
2366
2367 bacpy(&ev.addr.bdaddr, bdaddr);
2368 ev.addr.type = addr_type;
2369
2370 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002372}
2373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002377 struct mgmt_cp_unpair_device *cp = data;
2378 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002379 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002380 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002381 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002382 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002383 int err;
2384
Johan Hedberga8a1d192011-11-10 15:54:38 +02002385 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002386 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2387 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002388
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002389 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002390 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2391 MGMT_STATUS_INVALID_PARAMS,
2392 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002393
Johan Hedberg118da702013-01-20 14:27:20 +02002394 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002395 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2396 MGMT_STATUS_INVALID_PARAMS,
2397 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002398
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399 hci_dev_lock(hdev);
2400
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002401 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002402 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2403 MGMT_STATUS_NOT_POWERED, &rp,
2404 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002405 goto unlock;
2406 }
2407
Johan Hedberge0b2b272014-02-18 17:14:31 +02002408 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002409 /* If disconnection is requested, then look up the
2410 * connection. If the remote device is connected, it
2411 * will be later used to terminate the link.
2412 *
2413 * Setting it to NULL explicitly will cause no
2414 * termination of the link.
2415 */
2416 if (cp->disconnect)
2417 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2418 &cp->addr.bdaddr);
2419 else
2420 conn = NULL;
2421
Johan Hedberg124f6e32012-02-09 13:50:12 +02002422 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002423 if (err < 0) {
2424 err = mgmt_cmd_complete(sk, hdev->id,
2425 MGMT_OP_UNPAIR_DEVICE,
2426 MGMT_STATUS_NOT_PAIRED, &rp,
2427 sizeof(rp));
2428 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002429 }
2430
Johan Hedbergec182f02015-10-21 18:03:03 +03002431 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002432 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002433
Johan Hedbergec182f02015-10-21 18:03:03 +03002434 /* LE address type */
2435 addr_type = le_addr_type(cp->addr.type);
2436
2437 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2438
2439 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002440 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002441 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2442 MGMT_STATUS_NOT_PAIRED, &rp,
2443 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002444 goto unlock;
2445 }
2446
Johan Hedbergec182f02015-10-21 18:03:03 +03002447 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2448 if (!conn) {
2449 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2450 goto done;
2451 }
2452
Johan Hedbergc81d5552015-10-22 09:38:35 +03002453 /* Abort any ongoing SMP pairing */
2454 smp_cancel_pairing(conn);
2455
Johan Hedbergec182f02015-10-21 18:03:03 +03002456 /* Defer clearing up the connection parameters until closing to
2457 * give a chance of keeping them if a repairing happens.
2458 */
2459 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2460
Johan Hedbergfc643612015-10-22 09:38:31 +03002461 /* Disable auto-connection parameters if present */
2462 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2463 if (params) {
2464 if (params->explicit_connect)
2465 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2466 else
2467 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2468 }
2469
Johan Hedbergec182f02015-10-21 18:03:03 +03002470 /* If disconnection is not requested, then clear the connection
2471 * variable so that the link is not terminated.
2472 */
2473 if (!cp->disconnect)
2474 conn = NULL;
2475
2476done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002477 /* If the connection variable is set, then termination of the
2478 * link is requested.
2479 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002480 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002481 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2482 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002483 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002484 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002485 }
2486
Johan Hedberg124f6e32012-02-09 13:50:12 +02002487 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002488 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002489 if (!cmd) {
2490 err = -ENOMEM;
2491 goto unlock;
2492 }
2493
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002494 cmd->cmd_complete = addr_cmd_complete;
2495
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002496 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002497 if (err < 0)
2498 mgmt_pending_remove(cmd);
2499
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002500unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002502 return err;
2503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002508 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002509 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002510 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002511 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002512 int err;
2513
2514 BT_DBG("");
2515
Johan Hedberg06a63b12013-01-20 14:27:21 +02002516 memset(&rp, 0, sizeof(rp));
2517 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2518 rp.addr.type = cp->addr.type;
2519
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002520 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002521 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2522 MGMT_STATUS_INVALID_PARAMS,
2523 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002526
2527 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002528 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2529 MGMT_STATUS_NOT_POWERED, &rp,
2530 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002531 goto failed;
2532 }
2533
Johan Hedberg333ae952015-03-17 13:48:47 +02002534 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002535 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2536 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002537 goto failed;
2538 }
2539
Andre Guedes591f47f2012-04-24 21:02:49 -03002540 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002541 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2542 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002543 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002544 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2545 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002546
Vishal Agarwalf9607272012-06-13 05:32:43 +05302547 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002548 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2549 MGMT_STATUS_NOT_CONNECTED, &rp,
2550 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002551 goto failed;
2552 }
2553
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002554 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002555 if (!cmd) {
2556 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002557 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002558 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002559
Johan Hedbergf5818c22014-12-05 13:36:02 +02002560 cmd->cmd_complete = generic_cmd_complete;
2561
Johan Hedberge3f2f922014-08-18 20:33:33 +03002562 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002563 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002564 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002565
2566failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002567 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002568 return err;
2569}
2570
Andre Guedes57c14772012-04-24 21:02:50 -03002571static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002572{
2573 switch (link_type) {
2574 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002575 switch (addr_type) {
2576 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002577 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002578
Johan Hedberg48264f02011-11-09 13:58:58 +02002579 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002580 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002581 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002582 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002583
Johan Hedberg4c659c32011-11-07 23:13:39 +02002584 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002585 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002586 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002587 }
2588}
2589
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2591 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002592{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002593 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002594 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002595 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002596 int err;
2597 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002598
2599 BT_DBG("");
2600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002602
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002603 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002604 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2605 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002606 goto unlock;
2607 }
2608
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002609 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002610 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2611 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002612 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002613 }
2614
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002615 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002616 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002617 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002618 err = -ENOMEM;
2619 goto unlock;
2620 }
2621
Johan Hedberg2784eb42011-01-21 13:56:35 +02002622 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002623 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002624 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2625 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002626 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002627 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002628 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002629 continue;
2630 i++;
2631 }
2632
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002633 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002634
Johan Hedberg4c659c32011-11-07 23:13:39 +02002635 /* Recalculate length in case of filtered SCO connections, etc */
2636 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002637
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002638 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2639 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002640
Johan Hedberga38528f2011-01-22 06:46:43 +02002641 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002642
2643unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002644 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002645 return err;
2646}
2647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002650{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002651 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002652 int err;
2653
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002654 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002655 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002656 if (!cmd)
2657 return -ENOMEM;
2658
Johan Hedbergd8457692012-02-17 14:24:57 +02002659 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002660 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002661 if (err < 0)
2662 mgmt_pending_remove(cmd);
2663
2664 return err;
2665}
2666
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002667static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002668 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002669{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002670 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002671 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002672 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002673 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002674 int err;
2675
2676 BT_DBG("");
2677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002678 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002679
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002680 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002681 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2682 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002683 goto failed;
2684 }
2685
Johan Hedbergd8457692012-02-17 14:24:57 +02002686 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002687 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002688 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2689 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002690 goto failed;
2691 }
2692
2693 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002694 struct mgmt_cp_pin_code_neg_reply ncp;
2695
2696 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002697
2698 BT_ERR("PIN code is not 16 bytes long");
2699
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002700 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002701 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002702 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2703 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002704
2705 goto failed;
2706 }
2707
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002708 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002709 if (!cmd) {
2710 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002712 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002713
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002714 cmd->cmd_complete = addr_cmd_complete;
2715
Johan Hedbergd8457692012-02-17 14:24:57 +02002716 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002718 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002719
2720 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2721 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002722 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002723
2724failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002725 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002726 return err;
2727}
2728
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2730 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002731{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002732 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002733
2734 BT_DBG("");
2735
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002736 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002737 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2738 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002739
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002740 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002741
2742 hdev->io_capability = cp->io_capability;
2743
2744 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002745 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002746
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002747 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002748
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002749 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2750 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002751}
2752
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002753static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002754{
2755 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002756 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002757
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002758 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002759 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2760 continue;
2761
Johan Hedberge9a416b2011-02-19 12:05:56 -03002762 if (cmd->user_data != conn)
2763 continue;
2764
2765 return cmd;
2766 }
2767
2768 return NULL;
2769}
2770
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002771static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002772{
2773 struct mgmt_rp_pair_device rp;
2774 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002775 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002776
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002777 bacpy(&rp.addr.bdaddr, &conn->dst);
2778 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002779
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002780 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2781 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002782
2783 /* So we don't get further callbacks for this connection */
2784 conn->connect_cfm_cb = NULL;
2785 conn->security_cfm_cb = NULL;
2786 conn->disconn_cfm_cb = NULL;
2787
David Herrmann76a68ba2013-04-06 20:28:37 +02002788 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002789
2790 /* The device is paired so there is no need to remove
2791 * its connection parameters anymore.
2792 */
2793 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002794
2795 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002796
2797 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002798}
2799
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002800void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2801{
2802 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002803 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002804
2805 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002806 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002807 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002808 mgmt_pending_remove(cmd);
2809 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002810}
2811
Johan Hedberge9a416b2011-02-19 12:05:56 -03002812static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2813{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002814 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002815
2816 BT_DBG("status %u", status);
2817
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002818 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002819 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002820 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002821 return;
2822 }
2823
2824 cmd->cmd_complete(cmd, mgmt_status(status));
2825 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002826}
2827
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002828static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302829{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002830 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302831
2832 BT_DBG("status %u", status);
2833
2834 if (!status)
2835 return;
2836
2837 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002838 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302839 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002840 return;
2841 }
2842
2843 cmd->cmd_complete(cmd, mgmt_status(status));
2844 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302845}
2846
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002847static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002848 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002849{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002850 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002851 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002852 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002853 u8 sec_level, auth_type;
2854 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002855 int err;
2856
2857 BT_DBG("");
2858
Szymon Jancf950a30e2013-01-18 12:48:07 +01002859 memset(&rp, 0, sizeof(rp));
2860 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2861 rp.addr.type = cp->addr.type;
2862
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002863 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002864 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2865 MGMT_STATUS_INVALID_PARAMS,
2866 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002867
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002868 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002869 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2870 MGMT_STATUS_INVALID_PARAMS,
2871 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002873 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002874
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002875 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002876 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2877 MGMT_STATUS_NOT_POWERED, &rp,
2878 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002879 goto unlock;
2880 }
2881
Johan Hedberg55e76b32015-03-10 22:34:40 +02002882 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2883 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2884 MGMT_STATUS_ALREADY_PAIRED, &rp,
2885 sizeof(rp));
2886 goto unlock;
2887 }
2888
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002889 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002890 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002891
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002892 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002893 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2894 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002895 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002896 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002897 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002898
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002899 /* When pairing a new device, it is expected to remember
2900 * this device for future connections. Adding the connection
2901 * parameter information ahead of time allows tracking
2902 * of the slave preferred values and will speed up any
2903 * further connection establishment.
2904 *
2905 * If connection parameters already exist, then they
2906 * will be kept and this function does nothing.
2907 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002908 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2909
2910 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2911 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002912
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002913 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2914 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002915 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002916 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002917
Ville Tervo30e76272011-02-22 16:10:53 -03002918 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002919 int status;
2920
2921 if (PTR_ERR(conn) == -EBUSY)
2922 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002923 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2924 status = MGMT_STATUS_NOT_SUPPORTED;
2925 else if (PTR_ERR(conn) == -ECONNREFUSED)
2926 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002927 else
2928 status = MGMT_STATUS_CONNECT_FAILED;
2929
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002930 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2931 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002932 goto unlock;
2933 }
2934
2935 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002936 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002937 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2938 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002939 goto unlock;
2940 }
2941
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002942 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002943 if (!cmd) {
2944 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002945 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002946 goto unlock;
2947 }
2948
Johan Hedberg04ab2742014-12-05 13:36:04 +02002949 cmd->cmd_complete = pairing_complete;
2950
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002951 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002952 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002953 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002954 conn->security_cfm_cb = pairing_complete_cb;
2955 conn->disconn_cfm_cb = pairing_complete_cb;
2956 } else {
2957 conn->connect_cfm_cb = le_pairing_complete_cb;
2958 conn->security_cfm_cb = le_pairing_complete_cb;
2959 conn->disconn_cfm_cb = le_pairing_complete_cb;
2960 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002961
Johan Hedberge9a416b2011-02-19 12:05:56 -03002962 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002963 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002964
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002965 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002966 hci_conn_security(conn, sec_level, auth_type, true)) {
2967 cmd->cmd_complete(cmd, 0);
2968 mgmt_pending_remove(cmd);
2969 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002970
2971 err = 0;
2972
2973unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002974 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002975 return err;
2976}
2977
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002978static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2979 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002980{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002981 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002982 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002983 struct hci_conn *conn;
2984 int err;
2985
2986 BT_DBG("");
2987
Johan Hedberg28424702012-02-02 04:02:29 +02002988 hci_dev_lock(hdev);
2989
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002990 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002991 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2992 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002993 goto unlock;
2994 }
2995
Johan Hedberg333ae952015-03-17 13:48:47 +02002996 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002997 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002998 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2999 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003000 goto unlock;
3001 }
3002
3003 conn = cmd->user_data;
3004
3005 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003006 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3007 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003008 goto unlock;
3009 }
3010
Johan Hedberga511b352014-12-11 21:45:45 +02003011 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3012 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003013
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003014 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3015 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003016unlock:
3017 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003018 return err;
3019}
3020
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003021static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003022 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003024{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003025 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003026 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003027 int err;
3028
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003029 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003030
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003031 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003032 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3033 MGMT_STATUS_NOT_POWERED, addr,
3034 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003035 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003036 }
3037
Johan Hedberg1707c602013-03-15 17:07:15 -05003038 if (addr->type == BDADDR_BREDR)
3039 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003040 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03003041 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
3042 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08003043
Johan Hedberg272d90d2012-02-09 15:26:12 +02003044 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003045 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3046 MGMT_STATUS_NOT_CONNECTED, addr,
3047 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003048 goto done;
3049 }
3050
Johan Hedberg1707c602013-03-15 17:07:15 -05003051 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003052 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003053 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003054 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3055 MGMT_STATUS_SUCCESS, addr,
3056 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003057 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003058 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3059 MGMT_STATUS_FAILED, addr,
3060 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003061
Brian Gix47c15e22011-11-16 13:53:14 -08003062 goto done;
3063 }
3064
Johan Hedberg1707c602013-03-15 17:07:15 -05003065 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003066 if (!cmd) {
3067 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003068 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003069 }
3070
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003071 cmd->cmd_complete = addr_cmd_complete;
3072
Brian Gix0df4c182011-11-16 13:53:13 -08003073 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003074 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3075 struct hci_cp_user_passkey_reply cp;
3076
Johan Hedberg1707c602013-03-15 17:07:15 -05003077 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003078 cp.passkey = passkey;
3079 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3080 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003081 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3082 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003083
Johan Hedberga664b5b2011-02-19 12:06:02 -03003084 if (err < 0)
3085 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003086
Brian Gix0df4c182011-11-16 13:53:13 -08003087done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003088 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003089 return err;
3090}
3091
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303092static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3093 void *data, u16 len)
3094{
3095 struct mgmt_cp_pin_code_neg_reply *cp = data;
3096
3097 BT_DBG("");
3098
Johan Hedberg1707c602013-03-15 17:07:15 -05003099 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303100 MGMT_OP_PIN_CODE_NEG_REPLY,
3101 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3102}
3103
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003104static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3105 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003106{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003107 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003108
3109 BT_DBG("");
3110
3111 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003112 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3113 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003114
Johan Hedberg1707c602013-03-15 17:07:15 -05003115 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003116 MGMT_OP_USER_CONFIRM_REPLY,
3117 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003118}
3119
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003120static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003121 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003122{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003123 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003124
3125 BT_DBG("");
3126
Johan Hedberg1707c602013-03-15 17:07:15 -05003127 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003128 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3129 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003130}
3131
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3133 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003134{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003135 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003136
3137 BT_DBG("");
3138
Johan Hedberg1707c602013-03-15 17:07:15 -05003139 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003140 MGMT_OP_USER_PASSKEY_REPLY,
3141 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003142}
3143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003147 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003148
3149 BT_DBG("");
3150
Johan Hedberg1707c602013-03-15 17:07:15 -05003151 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3153 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003154}
3155
Marcel Holtmann1904a852015-01-11 13:50:44 -08003156static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003157{
3158 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003159 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003160
3161 BT_DBG("status 0x%02x", status);
3162
3163 hci_dev_lock(hdev);
3164
Johan Hedberg333ae952015-03-17 13:48:47 +02003165 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003166 if (!cmd)
3167 goto unlock;
3168
3169 cp = cmd->param;
3170
3171 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003172 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3173 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003174 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003175 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3176 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003177
3178 mgmt_pending_remove(cmd);
3179
3180unlock:
3181 hci_dev_unlock(hdev);
3182}
3183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003184static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003185 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003186{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003187 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003188 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003189 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003190 int err;
3191
3192 BT_DBG("");
3193
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003194 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003195
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003196 /* If the old values are the same as the new ones just return a
3197 * direct command complete event.
3198 */
3199 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3200 !memcmp(hdev->short_name, cp->short_name,
3201 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003202 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3203 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003204 goto failed;
3205 }
3206
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003207 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003208
Johan Hedbergb5235a62012-02-21 14:32:24 +02003209 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003210 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003211
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003212 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3213 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003214 if (err < 0)
3215 goto failed;
3216
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003217 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3218 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003219
Johan Hedbergb5235a62012-02-21 14:32:24 +02003220 goto failed;
3221 }
3222
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003223 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003224 if (!cmd) {
3225 err = -ENOMEM;
3226 goto failed;
3227 }
3228
Johan Hedberg13928972013-03-15 17:07:00 -05003229 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3230
Johan Hedberg890ea892013-03-15 17:06:52 -05003231 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003232
3233 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003234 __hci_req_update_name(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003235 update_eir(&req);
3236 }
3237
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003238 /* The name is stored in the scan response data and so
3239 * no need to udpate the advertising data here.
3240 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003241 if (lmp_le_capable(hdev))
Johan Hedbergf2252572015-11-18 12:49:20 +02003242 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Johan Hedberg3f985052013-03-15 17:07:02 -05003243
Johan Hedberg13928972013-03-15 17:07:00 -05003244 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003245 if (err < 0)
3246 mgmt_pending_remove(cmd);
3247
3248failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003249 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003250 return err;
3251}
3252
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003253static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3254 u16 opcode, struct sk_buff *skb)
3255{
3256 struct mgmt_rp_read_local_oob_data mgmt_rp;
3257 size_t rp_size = sizeof(mgmt_rp);
3258 struct mgmt_pending_cmd *cmd;
3259
3260 BT_DBG("%s status %u", hdev->name, status);
3261
3262 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3263 if (!cmd)
3264 return;
3265
3266 if (status || !skb) {
3267 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3268 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3269 goto remove;
3270 }
3271
3272 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3273
3274 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3275 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3276
3277 if (skb->len < sizeof(*rp)) {
3278 mgmt_cmd_status(cmd->sk, hdev->id,
3279 MGMT_OP_READ_LOCAL_OOB_DATA,
3280 MGMT_STATUS_FAILED);
3281 goto remove;
3282 }
3283
3284 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3285 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3286
3287 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3288 } else {
3289 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3290
3291 if (skb->len < sizeof(*rp)) {
3292 mgmt_cmd_status(cmd->sk, hdev->id,
3293 MGMT_OP_READ_LOCAL_OOB_DATA,
3294 MGMT_STATUS_FAILED);
3295 goto remove;
3296 }
3297
3298 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3299 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3300
3301 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3302 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3303 }
3304
3305 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3306 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3307
3308remove:
3309 mgmt_pending_remove(cmd);
3310}
3311
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003312static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003313 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003314{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003315 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003316 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003317 int err;
3318
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003319 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003320
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003321 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003322
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003323 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003324 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3325 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003326 goto unlock;
3327 }
3328
Andre Guedes9a1a1992012-07-24 15:03:48 -03003329 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003330 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3331 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003332 goto unlock;
3333 }
3334
Johan Hedberg333ae952015-03-17 13:48:47 +02003335 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003336 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3337 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003338 goto unlock;
3339 }
3340
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003341 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003342 if (!cmd) {
3343 err = -ENOMEM;
3344 goto unlock;
3345 }
3346
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003347 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003348
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003349 if (bredr_sc_enabled(hdev))
3350 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3351 else
3352 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3353
3354 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003355 if (err < 0)
3356 mgmt_pending_remove(cmd);
3357
3358unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003359 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003360 return err;
3361}
3362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003363static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003364 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003365{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003366 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003367 int err;
3368
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003369 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003370
Johan Hedberg5d57e792015-01-23 10:10:38 +02003371 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003372 return mgmt_cmd_complete(sk, hdev->id,
3373 MGMT_OP_ADD_REMOTE_OOB_DATA,
3374 MGMT_STATUS_INVALID_PARAMS,
3375 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003376
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003377 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003378
Marcel Holtmannec109112014-01-10 02:07:30 -08003379 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3380 struct mgmt_cp_add_remote_oob_data *cp = data;
3381 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003382
Johan Hedbergc19a4952014-11-17 20:52:19 +02003383 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003384 err = mgmt_cmd_complete(sk, hdev->id,
3385 MGMT_OP_ADD_REMOTE_OOB_DATA,
3386 MGMT_STATUS_INVALID_PARAMS,
3387 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003388 goto unlock;
3389 }
3390
Marcel Holtmannec109112014-01-10 02:07:30 -08003391 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003392 cp->addr.type, cp->hash,
3393 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003394 if (err < 0)
3395 status = MGMT_STATUS_FAILED;
3396 else
3397 status = MGMT_STATUS_SUCCESS;
3398
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003399 err = mgmt_cmd_complete(sk, hdev->id,
3400 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3401 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003402 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3403 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003404 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003405 u8 status;
3406
Johan Hedberg86df9202014-10-26 20:52:27 +01003407 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003408 /* Enforce zero-valued 192-bit parameters as
3409 * long as legacy SMP OOB isn't implemented.
3410 */
3411 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3412 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003413 err = mgmt_cmd_complete(sk, hdev->id,
3414 MGMT_OP_ADD_REMOTE_OOB_DATA,
3415 MGMT_STATUS_INVALID_PARAMS,
3416 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003417 goto unlock;
3418 }
3419
Johan Hedberg86df9202014-10-26 20:52:27 +01003420 rand192 = NULL;
3421 hash192 = NULL;
3422 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003423 /* In case one of the P-192 values is set to zero,
3424 * then just disable OOB data for P-192.
3425 */
3426 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3427 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3428 rand192 = NULL;
3429 hash192 = NULL;
3430 } else {
3431 rand192 = cp->rand192;
3432 hash192 = cp->hash192;
3433 }
3434 }
3435
3436 /* In case one of the P-256 values is set to zero, then just
3437 * disable OOB data for P-256.
3438 */
3439 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3440 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3441 rand256 = NULL;
3442 hash256 = NULL;
3443 } else {
3444 rand256 = cp->rand256;
3445 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003446 }
3447
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003448 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003449 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003450 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003451 if (err < 0)
3452 status = MGMT_STATUS_FAILED;
3453 else
3454 status = MGMT_STATUS_SUCCESS;
3455
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003456 err = mgmt_cmd_complete(sk, hdev->id,
3457 MGMT_OP_ADD_REMOTE_OOB_DATA,
3458 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003459 } else {
3460 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003461 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3462 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003463 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003464
Johan Hedbergc19a4952014-11-17 20:52:19 +02003465unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003466 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003467 return err;
3468}
3469
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003470static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003471 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003472{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003473 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003474 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003475 int err;
3476
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003477 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003478
Johan Hedbergc19a4952014-11-17 20:52:19 +02003479 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003480 return mgmt_cmd_complete(sk, hdev->id,
3481 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3482 MGMT_STATUS_INVALID_PARAMS,
3483 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003484
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003485 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003486
Johan Hedbergeedbd582014-11-15 09:34:23 +02003487 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3488 hci_remote_oob_data_clear(hdev);
3489 status = MGMT_STATUS_SUCCESS;
3490 goto done;
3491 }
3492
Johan Hedberg6928a922014-10-26 20:46:09 +01003493 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003494 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003495 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003496 else
Szymon Janca6785be2012-12-13 15:11:21 +01003497 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003498
Johan Hedbergeedbd582014-11-15 09:34:23 +02003499done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003500 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3501 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003502
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003503 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003504 return err;
3505}
3506
Johan Hedberge68f0722015-11-11 08:30:30 +02003507void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003508{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003509 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003510
Andre Guedes7c307722013-04-30 15:29:28 -03003511 BT_DBG("status %d", status);
3512
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003513 hci_dev_lock(hdev);
3514
Johan Hedberg333ae952015-03-17 13:48:47 +02003515 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003516 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003517 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003518
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003519 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003520 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003521 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003522 }
3523
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003524 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003525}
3526
Johan Hedberg591752a2015-11-11 08:11:24 +02003527static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3528 uint8_t *mgmt_status)
3529{
3530 switch (type) {
3531 case DISCOV_TYPE_LE:
3532 *mgmt_status = mgmt_le_support(hdev);
3533 if (*mgmt_status)
3534 return false;
3535 break;
3536 case DISCOV_TYPE_INTERLEAVED:
3537 *mgmt_status = mgmt_le_support(hdev);
3538 if (*mgmt_status)
3539 return false;
3540 /* Intentional fall-through */
3541 case DISCOV_TYPE_BREDR:
3542 *mgmt_status = mgmt_bredr_support(hdev);
3543 if (*mgmt_status)
3544 return false;
3545 break;
3546 default:
3547 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3548 return false;
3549 }
3550
3551 return true;
3552}
3553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003554static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003556{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003557 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003558 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003559 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003560 int err;
3561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003562 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003563
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003564 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003565
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003566 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003567 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3568 MGMT_STATUS_NOT_POWERED,
3569 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003570 goto failed;
3571 }
3572
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003573 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003574 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003575 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3576 MGMT_STATUS_BUSY, &cp->type,
3577 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003578 goto failed;
3579 }
3580
Johan Hedberg591752a2015-11-11 08:11:24 +02003581 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3582 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3583 status, &cp->type, sizeof(cp->type));
3584 goto failed;
3585 }
3586
Marcel Holtmann22078802014-12-05 11:45:22 +01003587 /* Clear the discovery filter first to free any previously
3588 * allocated memory for the UUID list.
3589 */
3590 hci_discovery_filter_clear(hdev);
3591
Andre Guedes4aab14e2012-02-17 20:39:36 -03003592 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003593 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003594
Johan Hedberge68f0722015-11-11 08:30:30 +02003595 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
3596 if (!cmd) {
3597 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003598 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003599 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003600
Johan Hedberge68f0722015-11-11 08:30:30 +02003601 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003602
3603 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003604 queue_work(hdev->req_workqueue, &hdev->discov_update);
3605 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003606
3607failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003608 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003609 return err;
3610}
3611
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003612static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3613 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003614{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003615 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3616 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003617}
3618
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003619static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3620 void *data, u16 len)
3621{
3622 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003623 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003624 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3625 u16 uuid_count, expected_len;
3626 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003627 int err;
3628
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003629 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003630
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003631 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003632
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003633 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003634 err = mgmt_cmd_complete(sk, hdev->id,
3635 MGMT_OP_START_SERVICE_DISCOVERY,
3636 MGMT_STATUS_NOT_POWERED,
3637 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003638 goto failed;
3639 }
3640
3641 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003642 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003643 err = mgmt_cmd_complete(sk, hdev->id,
3644 MGMT_OP_START_SERVICE_DISCOVERY,
3645 MGMT_STATUS_BUSY, &cp->type,
3646 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003647 goto failed;
3648 }
3649
3650 uuid_count = __le16_to_cpu(cp->uuid_count);
3651 if (uuid_count > max_uuid_count) {
3652 BT_ERR("service_discovery: too big uuid_count value %u",
3653 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003654 err = mgmt_cmd_complete(sk, hdev->id,
3655 MGMT_OP_START_SERVICE_DISCOVERY,
3656 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3657 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003658 goto failed;
3659 }
3660
3661 expected_len = sizeof(*cp) + uuid_count * 16;
3662 if (expected_len != len) {
3663 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3664 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003665 err = mgmt_cmd_complete(sk, hdev->id,
3666 MGMT_OP_START_SERVICE_DISCOVERY,
3667 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3668 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003669 goto failed;
3670 }
3671
Johan Hedberg591752a2015-11-11 08:11:24 +02003672 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3673 err = mgmt_cmd_complete(sk, hdev->id,
3674 MGMT_OP_START_SERVICE_DISCOVERY,
3675 status, &cp->type, sizeof(cp->type));
3676 goto failed;
3677 }
3678
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003679 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003680 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003681 if (!cmd) {
3682 err = -ENOMEM;
3683 goto failed;
3684 }
3685
Johan Hedberg2922a942014-12-05 13:36:06 +02003686 cmd->cmd_complete = service_discovery_cmd_complete;
3687
Marcel Holtmann22078802014-12-05 11:45:22 +01003688 /* Clear the discovery filter first to free any previously
3689 * allocated memory for the UUID list.
3690 */
3691 hci_discovery_filter_clear(hdev);
3692
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003693 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003694 hdev->discovery.type = cp->type;
3695 hdev->discovery.rssi = cp->rssi;
3696 hdev->discovery.uuid_count = uuid_count;
3697
3698 if (uuid_count > 0) {
3699 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3700 GFP_KERNEL);
3701 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003702 err = mgmt_cmd_complete(sk, hdev->id,
3703 MGMT_OP_START_SERVICE_DISCOVERY,
3704 MGMT_STATUS_FAILED,
3705 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003706 mgmt_pending_remove(cmd);
3707 goto failed;
3708 }
3709 }
3710
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003711 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003712 queue_work(hdev->req_workqueue, &hdev->discov_update);
3713 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003714
3715failed:
3716 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003717 return err;
3718}
3719
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003720void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003721{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003722 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003723
Andre Guedes0e05bba2013-04-30 15:29:33 -03003724 BT_DBG("status %d", status);
3725
3726 hci_dev_lock(hdev);
3727
Johan Hedberg333ae952015-03-17 13:48:47 +02003728 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003729 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003730 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003731 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003732 }
3733
Andre Guedes0e05bba2013-04-30 15:29:33 -03003734 hci_dev_unlock(hdev);
3735}
3736
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003737static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003738 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003739{
Johan Hedbergd9306502012-02-20 23:25:18 +02003740 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003741 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003742 int err;
3743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003744 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003745
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003746 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003747
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003748 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003749 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3750 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3751 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003752 goto unlock;
3753 }
3754
3755 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003756 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3757 MGMT_STATUS_INVALID_PARAMS,
3758 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003759 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003760 }
3761
Johan Hedberg2922a942014-12-05 13:36:06 +02003762 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003763 if (!cmd) {
3764 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003765 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003766 }
3767
Johan Hedberg2922a942014-12-05 13:36:06 +02003768 cmd->cmd_complete = generic_cmd_complete;
3769
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003770 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3771 queue_work(hdev->req_workqueue, &hdev->discov_update);
3772 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003773
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003774unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003775 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003776 return err;
3777}
3778
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003779static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003780 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003781{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003782 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003783 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003784 int err;
3785
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003786 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003787
Johan Hedberg561aafb2012-01-04 13:31:59 +02003788 hci_dev_lock(hdev);
3789
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003790 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003791 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3792 MGMT_STATUS_FAILED, &cp->addr,
3793 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003794 goto failed;
3795 }
3796
Johan Hedberga198e7b2012-02-17 14:27:06 +02003797 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003798 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003799 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3800 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3801 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003802 goto failed;
3803 }
3804
3805 if (cp->name_known) {
3806 e->name_state = NAME_KNOWN;
3807 list_del(&e->list);
3808 } else {
3809 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003810 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003811 }
3812
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003813 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3814 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003815
3816failed:
3817 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003818 return err;
3819}
3820
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003821static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003822 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003823{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003824 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003825 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003826 int err;
3827
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003828 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003829
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003830 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003831 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3832 MGMT_STATUS_INVALID_PARAMS,
3833 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003834
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003835 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003836
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003837 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3838 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003839 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003840 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003841 goto done;
3842 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003843
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003844 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3845 sk);
3846 status = MGMT_STATUS_SUCCESS;
3847
3848done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003849 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3850 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003851
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003852 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003853
3854 return err;
3855}
3856
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003857static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003858 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003859{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003860 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003861 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003862 int err;
3863
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003864 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003865
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003866 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003867 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3868 MGMT_STATUS_INVALID_PARAMS,
3869 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003871 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003872
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003873 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3874 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003875 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003876 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003877 goto done;
3878 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003879
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003880 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3881 sk);
3882 status = MGMT_STATUS_SUCCESS;
3883
3884done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003885 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3886 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003888 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003889
3890 return err;
3891}
3892
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003893static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3894 u16 len)
3895{
3896 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003897 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003898 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003899 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003900
3901 BT_DBG("%s", hdev->name);
3902
Szymon Jancc72d4b82012-03-16 16:02:57 +01003903 source = __le16_to_cpu(cp->source);
3904
3905 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003906 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3907 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003908
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003909 hci_dev_lock(hdev);
3910
Szymon Jancc72d4b82012-03-16 16:02:57 +01003911 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003912 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3913 hdev->devid_product = __le16_to_cpu(cp->product);
3914 hdev->devid_version = __le16_to_cpu(cp->version);
3915
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003916 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3917 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003918
Johan Hedberg890ea892013-03-15 17:06:52 -05003919 hci_req_init(&req, hdev);
3920 update_eir(&req);
3921 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003922
3923 hci_dev_unlock(hdev);
3924
3925 return err;
3926}
3927
Arman Uguray24b4f382015-03-23 15:57:12 -07003928static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3929 u16 opcode)
3930{
3931 BT_DBG("status %d", status);
3932}
3933
Marcel Holtmann1904a852015-01-11 13:50:44 -08003934static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3935 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003936{
3937 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003938 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003939 u8 instance;
3940 struct adv_info *adv_instance;
3941 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003942
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303943 hci_dev_lock(hdev);
3944
Johan Hedberg4375f102013-09-25 13:26:10 +03003945 if (status) {
3946 u8 mgmt_err = mgmt_status(status);
3947
3948 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3949 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303950 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003951 }
3952
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003953 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003954 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003955 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003956 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003957
Johan Hedberg4375f102013-09-25 13:26:10 +03003958 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3959 &match);
3960
3961 new_settings(hdev, match.sk);
3962
3963 if (match.sk)
3964 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303965
Arman Uguray24b4f382015-03-23 15:57:12 -07003966 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003967 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003968 */
3969 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003970 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
3971 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003972 goto unlock;
3973
Florian Grandel7816b822015-06-18 03:16:45 +02003974 instance = hdev->cur_adv_instance;
3975 if (!instance) {
3976 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3977 struct adv_info, list);
3978 if (!adv_instance)
3979 goto unlock;
3980
3981 instance = adv_instance->instance;
3982 }
3983
Arman Uguray24b4f382015-03-23 15:57:12 -07003984 hci_req_init(&req, hdev);
3985
Johan Hedbergf2252572015-11-18 12:49:20 +02003986 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003987
Florian Grandel7816b822015-06-18 03:16:45 +02003988 if (!err)
3989 err = hci_req_run(&req, enable_advertising_instance);
3990
3991 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003992 BT_ERR("Failed to re-configure advertising");
3993
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303994unlock:
3995 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003996}
3997
Marcel Holtmann21b51872013-10-10 09:47:53 -07003998static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3999 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004000{
4001 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004002 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004003 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004004 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004005 int err;
4006
4007 BT_DBG("request for %s", hdev->name);
4008
Johan Hedberge6fe7982013-10-02 15:45:22 +03004009 status = mgmt_le_support(hdev);
4010 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004011 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4012 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004013
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004014 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004015 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4016 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004017
4018 hci_dev_lock(hdev);
4019
4020 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004021
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004022 /* The following conditions are ones which mean that we should
4023 * not do any HCI communication but directly send a mgmt
4024 * response to user space (after toggling the flag if
4025 * necessary).
4026 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004027 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004028 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4029 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004030 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004031 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004032 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004033 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004034
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004035 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004036 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004037 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004038 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004039 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004040 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004041 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004042 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004043 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004044 }
4045
4046 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4047 if (err < 0)
4048 goto unlock;
4049
4050 if (changed)
4051 err = new_settings(hdev, sk);
4052
4053 goto unlock;
4054 }
4055
Johan Hedberg333ae952015-03-17 13:48:47 +02004056 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4057 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004058 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4059 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004060 goto unlock;
4061 }
4062
4063 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4064 if (!cmd) {
4065 err = -ENOMEM;
4066 goto unlock;
4067 }
4068
4069 hci_req_init(&req, hdev);
4070
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004071 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004072 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004073 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004074 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004075
Florian Grandel7816b822015-06-18 03:16:45 +02004076 cancel_adv_timeout(hdev);
4077
Arman Uguray24b4f382015-03-23 15:57:12 -07004078 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02004079 /* Switch to instance "0" for the Set Advertising setting.
4080 * We cannot use update_[adv|scan_rsp]_data() here as the
4081 * HCI_ADVERTISING flag is not yet set.
4082 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004083 __hci_req_update_adv_data(&req, 0x00);
4084 __hci_req_update_scan_rsp_data(&req, 0x00);
4085 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004086 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004087 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004088 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004089
4090 err = hci_req_run(&req, set_advertising_complete);
4091 if (err < 0)
4092 mgmt_pending_remove(cmd);
4093
4094unlock:
4095 hci_dev_unlock(hdev);
4096 return err;
4097}
4098
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004099static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4100 void *data, u16 len)
4101{
4102 struct mgmt_cp_set_static_address *cp = data;
4103 int err;
4104
4105 BT_DBG("%s", hdev->name);
4106
Marcel Holtmann62af4442013-10-02 22:10:32 -07004107 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004108 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4109 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004110
4111 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004112 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4113 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004114
4115 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4116 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004117 return mgmt_cmd_status(sk, hdev->id,
4118 MGMT_OP_SET_STATIC_ADDRESS,
4119 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004120
4121 /* Two most significant bits shall be set */
4122 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004123 return mgmt_cmd_status(sk, hdev->id,
4124 MGMT_OP_SET_STATIC_ADDRESS,
4125 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004126 }
4127
4128 hci_dev_lock(hdev);
4129
4130 bacpy(&hdev->static_addr, &cp->bdaddr);
4131
Marcel Holtmann93690c22015-03-06 10:11:21 -08004132 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4133 if (err < 0)
4134 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004135
Marcel Holtmann93690c22015-03-06 10:11:21 -08004136 err = new_settings(hdev, sk);
4137
4138unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004139 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004140 return err;
4141}
4142
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004143static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4144 void *data, u16 len)
4145{
4146 struct mgmt_cp_set_scan_params *cp = data;
4147 __u16 interval, window;
4148 int err;
4149
4150 BT_DBG("%s", hdev->name);
4151
4152 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004153 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4154 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004155
4156 interval = __le16_to_cpu(cp->interval);
4157
4158 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004159 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4160 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004161
4162 window = __le16_to_cpu(cp->window);
4163
4164 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004165 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4166 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004167
Marcel Holtmann899e1072013-10-14 09:55:32 -07004168 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004169 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4170 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004171
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004172 hci_dev_lock(hdev);
4173
4174 hdev->le_scan_interval = interval;
4175 hdev->le_scan_window = window;
4176
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004177 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4178 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004179
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004180 /* If background scan is running, restart it so new parameters are
4181 * loaded.
4182 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004183 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004184 hdev->discovery.state == DISCOVERY_STOPPED) {
4185 struct hci_request req;
4186
4187 hci_req_init(&req, hdev);
4188
4189 hci_req_add_le_scan_disable(&req);
4190 hci_req_add_le_passive_scan(&req);
4191
4192 hci_req_run(&req, NULL);
4193 }
4194
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004195 hci_dev_unlock(hdev);
4196
4197 return err;
4198}
4199
Marcel Holtmann1904a852015-01-11 13:50:44 -08004200static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4201 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004202{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004203 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004204
4205 BT_DBG("status 0x%02x", status);
4206
4207 hci_dev_lock(hdev);
4208
Johan Hedberg333ae952015-03-17 13:48:47 +02004209 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004210 if (!cmd)
4211 goto unlock;
4212
4213 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004214 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4215 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004216 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004217 struct mgmt_mode *cp = cmd->param;
4218
4219 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004220 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004221 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004222 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004223
Johan Hedberg33e38b32013-03-15 17:07:05 -05004224 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4225 new_settings(hdev, cmd->sk);
4226 }
4227
4228 mgmt_pending_remove(cmd);
4229
4230unlock:
4231 hci_dev_unlock(hdev);
4232}
4233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004234static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004235 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004236{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004237 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004238 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004239 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004240 int err;
4241
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004242 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004243
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004244 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004245 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004246 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4247 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004248
Johan Hedberga7e80f22013-01-09 16:05:19 +02004249 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004250 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4251 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004252
Antti Julkuf6422ec2011-06-22 13:11:56 +03004253 hci_dev_lock(hdev);
4254
Johan Hedberg333ae952015-03-17 13:48:47 +02004255 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004256 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4257 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004258 goto unlock;
4259 }
4260
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004261 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004262 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4263 hdev);
4264 goto unlock;
4265 }
4266
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004267 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004268 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004269 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4270 hdev);
4271 new_settings(hdev, sk);
4272 goto unlock;
4273 }
4274
Johan Hedberg33e38b32013-03-15 17:07:05 -05004275 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4276 data, len);
4277 if (!cmd) {
4278 err = -ENOMEM;
4279 goto unlock;
4280 }
4281
4282 hci_req_init(&req, hdev);
4283
Johan Hedberg406d7802013-03-15 17:07:09 -05004284 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004285
4286 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004287 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004288 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4289 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004290 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004291 }
4292
Johan Hedberg33e38b32013-03-15 17:07:05 -05004293unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004294 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004295
Antti Julkuf6422ec2011-06-22 13:11:56 +03004296 return err;
4297}
4298
Marcel Holtmann1904a852015-01-11 13:50:44 -08004299static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004300{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004301 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004302
4303 BT_DBG("status 0x%02x", status);
4304
4305 hci_dev_lock(hdev);
4306
Johan Hedberg333ae952015-03-17 13:48:47 +02004307 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004308 if (!cmd)
4309 goto unlock;
4310
4311 if (status) {
4312 u8 mgmt_err = mgmt_status(status);
4313
4314 /* We need to restore the flag if related HCI commands
4315 * failed.
4316 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004317 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004318
Johan Hedberga69e8372015-03-06 21:08:53 +02004319 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004320 } else {
4321 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4322 new_settings(hdev, cmd->sk);
4323 }
4324
4325 mgmt_pending_remove(cmd);
4326
4327unlock:
4328 hci_dev_unlock(hdev);
4329}
4330
4331static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4332{
4333 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004334 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004335 struct hci_request req;
4336 int err;
4337
4338 BT_DBG("request for %s", hdev->name);
4339
4340 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004341 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4342 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004343
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004344 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004345 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4346 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004347
4348 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004349 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4350 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004351
4352 hci_dev_lock(hdev);
4353
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004354 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004355 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4356 goto unlock;
4357 }
4358
4359 if (!hdev_is_powered(hdev)) {
4360 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004361 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4362 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4363 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4364 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4365 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004366 }
4367
Marcel Holtmannce05d602015-03-13 02:11:03 -07004368 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004369
4370 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4371 if (err < 0)
4372 goto unlock;
4373
4374 err = new_settings(hdev, sk);
4375 goto unlock;
4376 }
4377
4378 /* Reject disabling when powered on */
4379 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004380 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4381 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004382 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004383 } else {
4384 /* When configuring a dual-mode controller to operate
4385 * with LE only and using a static address, then switching
4386 * BR/EDR back on is not allowed.
4387 *
4388 * Dual-mode controllers shall operate with the public
4389 * address as its identity address for BR/EDR and LE. So
4390 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004391 *
4392 * The same restrictions applies when secure connections
4393 * has been enabled. For BR/EDR this is a controller feature
4394 * while for LE it is a host stack feature. This means that
4395 * switching BR/EDR back on when secure connections has been
4396 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004397 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004398 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004399 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004400 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004401 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4402 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004403 goto unlock;
4404 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004405 }
4406
Johan Hedberg333ae952015-03-17 13:48:47 +02004407 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004408 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4409 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004410 goto unlock;
4411 }
4412
4413 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4414 if (!cmd) {
4415 err = -ENOMEM;
4416 goto unlock;
4417 }
4418
Johan Hedbergf2252572015-11-18 12:49:20 +02004419 /* We need to flip the bit already here so that
4420 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004421 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004422 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004423
4424 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004425
Johan Hedberg432df052014-08-01 11:13:31 +03004426 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004427 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004428
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004429 /* Since only the advertising data flags will change, there
4430 * is no need to update the scan response data.
4431 */
Johan Hedbergf2252572015-11-18 12:49:20 +02004432 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004433
Johan Hedberg0663ca22013-10-02 13:43:14 +03004434 err = hci_req_run(&req, set_bredr_complete);
4435 if (err < 0)
4436 mgmt_pending_remove(cmd);
4437
4438unlock:
4439 hci_dev_unlock(hdev);
4440 return err;
4441}
4442
Johan Hedberga1443f52015-01-23 15:42:46 +02004443static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4444{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004445 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004446 struct mgmt_mode *cp;
4447
4448 BT_DBG("%s status %u", hdev->name, status);
4449
4450 hci_dev_lock(hdev);
4451
Johan Hedberg333ae952015-03-17 13:48:47 +02004452 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004453 if (!cmd)
4454 goto unlock;
4455
4456 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004457 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4458 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004459 goto remove;
4460 }
4461
4462 cp = cmd->param;
4463
4464 switch (cp->val) {
4465 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004466 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4467 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004468 break;
4469 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004470 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004471 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004472 break;
4473 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004474 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4475 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004476 break;
4477 }
4478
4479 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4480 new_settings(hdev, cmd->sk);
4481
4482remove:
4483 mgmt_pending_remove(cmd);
4484unlock:
4485 hci_dev_unlock(hdev);
4486}
4487
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004488static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4489 void *data, u16 len)
4490{
4491 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004492 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004493 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004494 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004495 int err;
4496
4497 BT_DBG("request for %s", hdev->name);
4498
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004499 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004500 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004501 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4502 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004503
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004504 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004505 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004506 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004507 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4508 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004509
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004510 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004511 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004512 MGMT_STATUS_INVALID_PARAMS);
4513
4514 hci_dev_lock(hdev);
4515
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004516 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004517 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004518 bool changed;
4519
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004520 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004521 changed = !hci_dev_test_and_set_flag(hdev,
4522 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004523 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004524 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004525 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004526 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004527 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004528 changed = hci_dev_test_and_clear_flag(hdev,
4529 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004530 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004531 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004532
4533 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4534 if (err < 0)
4535 goto failed;
4536
4537 if (changed)
4538 err = new_settings(hdev, sk);
4539
4540 goto failed;
4541 }
4542
Johan Hedberg333ae952015-03-17 13:48:47 +02004543 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004544 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4545 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004546 goto failed;
4547 }
4548
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004549 val = !!cp->val;
4550
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004551 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4552 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004553 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4554 goto failed;
4555 }
4556
4557 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4558 if (!cmd) {
4559 err = -ENOMEM;
4560 goto failed;
4561 }
4562
Johan Hedberga1443f52015-01-23 15:42:46 +02004563 hci_req_init(&req, hdev);
4564 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4565 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004566 if (err < 0) {
4567 mgmt_pending_remove(cmd);
4568 goto failed;
4569 }
4570
4571failed:
4572 hci_dev_unlock(hdev);
4573 return err;
4574}
4575
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004576static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4577 void *data, u16 len)
4578{
4579 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004580 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004581 int err;
4582
4583 BT_DBG("request for %s", hdev->name);
4584
Johan Hedbergb97109792014-06-24 14:00:28 +03004585 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004586 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4587 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004588
4589 hci_dev_lock(hdev);
4590
4591 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004592 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004593 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004594 changed = hci_dev_test_and_clear_flag(hdev,
4595 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004596
Johan Hedbergb97109792014-06-24 14:00:28 +03004597 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004598 use_changed = !hci_dev_test_and_set_flag(hdev,
4599 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004600 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004601 use_changed = hci_dev_test_and_clear_flag(hdev,
4602 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004603
4604 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004605 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004606 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4607 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4608 sizeof(mode), &mode);
4609 }
4610
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004611 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4612 if (err < 0)
4613 goto unlock;
4614
4615 if (changed)
4616 err = new_settings(hdev, sk);
4617
4618unlock:
4619 hci_dev_unlock(hdev);
4620 return err;
4621}
4622
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004623static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4624 u16 len)
4625{
4626 struct mgmt_cp_set_privacy *cp = cp_data;
4627 bool changed;
4628 int err;
4629
4630 BT_DBG("request for %s", hdev->name);
4631
4632 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004633 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4634 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004635
4636 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004637 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4638 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004639
4640 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004641 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4642 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004643
4644 hci_dev_lock(hdev);
4645
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004646 /* If user space supports this command it is also expected to
4647 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4648 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004649 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004650
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004651 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004652 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004653 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004654 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004655 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004656 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004657 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004658 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004659 }
4660
4661 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4662 if (err < 0)
4663 goto unlock;
4664
4665 if (changed)
4666 err = new_settings(hdev, sk);
4667
4668unlock:
4669 hci_dev_unlock(hdev);
4670 return err;
4671}
4672
Johan Hedberg41edf162014-02-18 10:19:35 +02004673static bool irk_is_valid(struct mgmt_irk_info *irk)
4674{
4675 switch (irk->addr.type) {
4676 case BDADDR_LE_PUBLIC:
4677 return true;
4678
4679 case BDADDR_LE_RANDOM:
4680 /* Two most significant bits shall be set */
4681 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4682 return false;
4683 return true;
4684 }
4685
4686 return false;
4687}
4688
4689static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4690 u16 len)
4691{
4692 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004693 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4694 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004695 u16 irk_count, expected_len;
4696 int i, err;
4697
4698 BT_DBG("request for %s", hdev->name);
4699
4700 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004701 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4702 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004703
4704 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004705 if (irk_count > max_irk_count) {
4706 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004707 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4708 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004709 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004710
4711 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4712 if (expected_len != len) {
4713 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004714 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004715 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4716 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004717 }
4718
4719 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4720
4721 for (i = 0; i < irk_count; i++) {
4722 struct mgmt_irk_info *key = &cp->irks[i];
4723
4724 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004725 return mgmt_cmd_status(sk, hdev->id,
4726 MGMT_OP_LOAD_IRKS,
4727 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004728 }
4729
4730 hci_dev_lock(hdev);
4731
4732 hci_smp_irks_clear(hdev);
4733
4734 for (i = 0; i < irk_count; i++) {
4735 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004736
Johan Hedberg85813a72015-10-21 18:02:59 +03004737 hci_add_irk(hdev, &irk->addr.bdaddr,
4738 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004739 BDADDR_ANY);
4740 }
4741
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004742 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004743
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004744 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004745
4746 hci_dev_unlock(hdev);
4747
4748 return err;
4749}
4750
Johan Hedberg3f706b72013-01-20 14:27:16 +02004751static bool ltk_is_valid(struct mgmt_ltk_info *key)
4752{
4753 if (key->master != 0x00 && key->master != 0x01)
4754 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004755
4756 switch (key->addr.type) {
4757 case BDADDR_LE_PUBLIC:
4758 return true;
4759
4760 case BDADDR_LE_RANDOM:
4761 /* Two most significant bits shall be set */
4762 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4763 return false;
4764 return true;
4765 }
4766
4767 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004768}
4769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004770static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004771 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004772{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004773 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004774 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4775 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004776 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004777 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004778
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004779 BT_DBG("request for %s", hdev->name);
4780
4781 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004782 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4783 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004784
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004785 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004786 if (key_count > max_key_count) {
4787 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004788 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4789 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004790 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004791
4792 expected_len = sizeof(*cp) + key_count *
4793 sizeof(struct mgmt_ltk_info);
4794 if (expected_len != len) {
4795 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004796 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004797 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4798 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004799 }
4800
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004801 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004802
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004803 for (i = 0; i < key_count; i++) {
4804 struct mgmt_ltk_info *key = &cp->keys[i];
4805
Johan Hedberg3f706b72013-01-20 14:27:16 +02004806 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004807 return mgmt_cmd_status(sk, hdev->id,
4808 MGMT_OP_LOAD_LONG_TERM_KEYS,
4809 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004810 }
4811
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004812 hci_dev_lock(hdev);
4813
4814 hci_smp_ltks_clear(hdev);
4815
4816 for (i = 0; i < key_count; i++) {
4817 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004818 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004819
Johan Hedberg61b43352014-05-29 19:36:53 +03004820 switch (key->type) {
4821 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004822 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004823 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004824 break;
4825 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004826 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004827 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004828 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004829 case MGMT_LTK_P256_UNAUTH:
4830 authenticated = 0x00;
4831 type = SMP_LTK_P256;
4832 break;
4833 case MGMT_LTK_P256_AUTH:
4834 authenticated = 0x01;
4835 type = SMP_LTK_P256;
4836 break;
4837 case MGMT_LTK_P256_DEBUG:
4838 authenticated = 0x00;
4839 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004840 default:
4841 continue;
4842 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004843
Johan Hedberg85813a72015-10-21 18:02:59 +03004844 hci_add_ltk(hdev, &key->addr.bdaddr,
4845 le_addr_type(key->addr.type), type, authenticated,
4846 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004847 }
4848
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004849 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004850 NULL, 0);
4851
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004852 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004853
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004854 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004855}
4856
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004857static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004858{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004859 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004860 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004861 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004862
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004863 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004864
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004865 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004866 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004867 rp.tx_power = conn->tx_power;
4868 rp.max_tx_power = conn->max_tx_power;
4869 } else {
4870 rp.rssi = HCI_RSSI_INVALID;
4871 rp.tx_power = HCI_TX_POWER_INVALID;
4872 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004873 }
4874
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004875 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4876 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004877
4878 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004879 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004880
4881 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004882}
4883
Marcel Holtmann1904a852015-01-11 13:50:44 -08004884static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4885 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004886{
4887 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004888 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004889 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004890 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004891 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004892
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004893 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004894
4895 hci_dev_lock(hdev);
4896
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004897 /* Commands sent in request are either Read RSSI or Read Transmit Power
4898 * Level so we check which one was last sent to retrieve connection
4899 * handle. Both commands have handle as first parameter so it's safe to
4900 * cast data on the same command struct.
4901 *
4902 * First command sent is always Read RSSI and we fail only if it fails.
4903 * In other case we simply override error to indicate success as we
4904 * already remembered if TX power value is actually valid.
4905 */
4906 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4907 if (!cp) {
4908 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004909 status = MGMT_STATUS_SUCCESS;
4910 } else {
4911 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004912 }
4913
4914 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004915 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004916 goto unlock;
4917 }
4918
4919 handle = __le16_to_cpu(cp->handle);
4920 conn = hci_conn_hash_lookup_handle(hdev, handle);
4921 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004922 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004923 goto unlock;
4924 }
4925
Johan Hedberg333ae952015-03-17 13:48:47 +02004926 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004927 if (!cmd)
4928 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004929
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004930 cmd->cmd_complete(cmd, status);
4931 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004932
4933unlock:
4934 hci_dev_unlock(hdev);
4935}
4936
4937static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4938 u16 len)
4939{
4940 struct mgmt_cp_get_conn_info *cp = data;
4941 struct mgmt_rp_get_conn_info rp;
4942 struct hci_conn *conn;
4943 unsigned long conn_info_age;
4944 int err = 0;
4945
4946 BT_DBG("%s", hdev->name);
4947
4948 memset(&rp, 0, sizeof(rp));
4949 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4950 rp.addr.type = cp->addr.type;
4951
4952 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004953 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4954 MGMT_STATUS_INVALID_PARAMS,
4955 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004956
4957 hci_dev_lock(hdev);
4958
4959 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004960 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4961 MGMT_STATUS_NOT_POWERED, &rp,
4962 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004963 goto unlock;
4964 }
4965
4966 if (cp->addr.type == BDADDR_BREDR)
4967 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4968 &cp->addr.bdaddr);
4969 else
4970 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4971
4972 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004973 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4974 MGMT_STATUS_NOT_CONNECTED, &rp,
4975 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004976 goto unlock;
4977 }
4978
Johan Hedberg333ae952015-03-17 13:48:47 +02004979 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004980 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4981 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004982 goto unlock;
4983 }
4984
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004985 /* To avoid client trying to guess when to poll again for information we
4986 * calculate conn info age as random value between min/max set in hdev.
4987 */
4988 conn_info_age = hdev->conn_info_min_age +
4989 prandom_u32_max(hdev->conn_info_max_age -
4990 hdev->conn_info_min_age);
4991
4992 /* Query controller to refresh cached values if they are too old or were
4993 * never read.
4994 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004995 if (time_after(jiffies, conn->conn_info_timestamp +
4996 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004997 !conn->conn_info_timestamp) {
4998 struct hci_request req;
4999 struct hci_cp_read_tx_power req_txp_cp;
5000 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005001 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005002
5003 hci_req_init(&req, hdev);
5004 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5005 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5006 &req_rssi_cp);
5007
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005008 /* For LE links TX power does not change thus we don't need to
5009 * query for it once value is known.
5010 */
5011 if (!bdaddr_type_is_le(cp->addr.type) ||
5012 conn->tx_power == HCI_TX_POWER_INVALID) {
5013 req_txp_cp.handle = cpu_to_le16(conn->handle);
5014 req_txp_cp.type = 0x00;
5015 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5016 sizeof(req_txp_cp), &req_txp_cp);
5017 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005018
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005019 /* Max TX power needs to be read only once per connection */
5020 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5021 req_txp_cp.handle = cpu_to_le16(conn->handle);
5022 req_txp_cp.type = 0x01;
5023 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5024 sizeof(req_txp_cp), &req_txp_cp);
5025 }
5026
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005027 err = hci_req_run(&req, conn_info_refresh_complete);
5028 if (err < 0)
5029 goto unlock;
5030
5031 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5032 data, len);
5033 if (!cmd) {
5034 err = -ENOMEM;
5035 goto unlock;
5036 }
5037
5038 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005039 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005040 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005041
5042 conn->conn_info_timestamp = jiffies;
5043 } else {
5044 /* Cache is valid, just reply with values cached in hci_conn */
5045 rp.rssi = conn->rssi;
5046 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005047 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005048
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005049 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5050 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005051 }
5052
5053unlock:
5054 hci_dev_unlock(hdev);
5055 return err;
5056}
5057
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005058static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005059{
5060 struct hci_conn *conn = cmd->user_data;
5061 struct mgmt_rp_get_clock_info rp;
5062 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005063 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005064
5065 memset(&rp, 0, sizeof(rp));
5066 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5067
5068 if (status)
5069 goto complete;
5070
5071 hdev = hci_dev_get(cmd->index);
5072 if (hdev) {
5073 rp.local_clock = cpu_to_le32(hdev->clock);
5074 hci_dev_put(hdev);
5075 }
5076
5077 if (conn) {
5078 rp.piconet_clock = cpu_to_le32(conn->clock);
5079 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5080 }
5081
5082complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005083 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5084 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005085
5086 if (conn) {
5087 hci_conn_drop(conn);
5088 hci_conn_put(conn);
5089 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005090
5091 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005092}
5093
Marcel Holtmann1904a852015-01-11 13:50:44 -08005094static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005095{
Johan Hedberg95868422014-06-28 17:54:07 +03005096 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005097 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005098 struct hci_conn *conn;
5099
5100 BT_DBG("%s status %u", hdev->name, status);
5101
5102 hci_dev_lock(hdev);
5103
5104 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5105 if (!hci_cp)
5106 goto unlock;
5107
5108 if (hci_cp->which) {
5109 u16 handle = __le16_to_cpu(hci_cp->handle);
5110 conn = hci_conn_hash_lookup_handle(hdev, handle);
5111 } else {
5112 conn = NULL;
5113 }
5114
Johan Hedberg333ae952015-03-17 13:48:47 +02005115 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005116 if (!cmd)
5117 goto unlock;
5118
Johan Hedberg69487372014-12-05 13:36:07 +02005119 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005120 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005121
5122unlock:
5123 hci_dev_unlock(hdev);
5124}
5125
5126static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5127 u16 len)
5128{
5129 struct mgmt_cp_get_clock_info *cp = data;
5130 struct mgmt_rp_get_clock_info rp;
5131 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005132 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005133 struct hci_request req;
5134 struct hci_conn *conn;
5135 int err;
5136
5137 BT_DBG("%s", hdev->name);
5138
5139 memset(&rp, 0, sizeof(rp));
5140 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5141 rp.addr.type = cp->addr.type;
5142
5143 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005144 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5145 MGMT_STATUS_INVALID_PARAMS,
5146 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005147
5148 hci_dev_lock(hdev);
5149
5150 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005151 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5152 MGMT_STATUS_NOT_POWERED, &rp,
5153 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005154 goto unlock;
5155 }
5156
5157 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5158 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5159 &cp->addr.bdaddr);
5160 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005161 err = mgmt_cmd_complete(sk, hdev->id,
5162 MGMT_OP_GET_CLOCK_INFO,
5163 MGMT_STATUS_NOT_CONNECTED,
5164 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005165 goto unlock;
5166 }
5167 } else {
5168 conn = NULL;
5169 }
5170
5171 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5172 if (!cmd) {
5173 err = -ENOMEM;
5174 goto unlock;
5175 }
5176
Johan Hedberg69487372014-12-05 13:36:07 +02005177 cmd->cmd_complete = clock_info_cmd_complete;
5178
Johan Hedberg95868422014-06-28 17:54:07 +03005179 hci_req_init(&req, hdev);
5180
5181 memset(&hci_cp, 0, sizeof(hci_cp));
5182 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5183
5184 if (conn) {
5185 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005186 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005187
5188 hci_cp.handle = cpu_to_le16(conn->handle);
5189 hci_cp.which = 0x01; /* Piconet clock */
5190 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5191 }
5192
5193 err = hci_req_run(&req, get_clock_info_complete);
5194 if (err < 0)
5195 mgmt_pending_remove(cmd);
5196
5197unlock:
5198 hci_dev_unlock(hdev);
5199 return err;
5200}
5201
Johan Hedberg5a154e62014-12-19 22:26:02 +02005202static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5203{
5204 struct hci_conn *conn;
5205
5206 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5207 if (!conn)
5208 return false;
5209
5210 if (conn->dst_type != type)
5211 return false;
5212
5213 if (conn->state != BT_CONNECTED)
5214 return false;
5215
5216 return true;
5217}
5218
5219/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005220static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005221 u8 addr_type, u8 auto_connect)
5222{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005223 struct hci_conn_params *params;
5224
5225 params = hci_conn_params_add(hdev, addr, addr_type);
5226 if (!params)
5227 return -EIO;
5228
5229 if (params->auto_connect == auto_connect)
5230 return 0;
5231
5232 list_del_init(&params->action);
5233
5234 switch (auto_connect) {
5235 case HCI_AUTO_CONN_DISABLED:
5236 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005237 /* If auto connect is being disabled when we're trying to
5238 * connect to device, keep connecting.
5239 */
5240 if (params->explicit_connect)
5241 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005242 break;
5243 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005244 if (params->explicit_connect)
5245 list_add(&params->action, &hdev->pend_le_conns);
5246 else
5247 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005248 break;
5249 case HCI_AUTO_CONN_DIRECT:
5250 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005251 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005252 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005253 break;
5254 }
5255
5256 params->auto_connect = auto_connect;
5257
5258 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5259 auto_connect);
5260
5261 return 0;
5262}
5263
Marcel Holtmann8afef092014-06-29 22:28:34 +02005264static void device_added(struct sock *sk, struct hci_dev *hdev,
5265 bdaddr_t *bdaddr, u8 type, u8 action)
5266{
5267 struct mgmt_ev_device_added ev;
5268
5269 bacpy(&ev.addr.bdaddr, bdaddr);
5270 ev.addr.type = type;
5271 ev.action = action;
5272
5273 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5274}
5275
Marcel Holtmann2faade52014-06-29 19:44:03 +02005276static int add_device(struct sock *sk, struct hci_dev *hdev,
5277 void *data, u16 len)
5278{
5279 struct mgmt_cp_add_device *cp = data;
5280 u8 auto_conn, addr_type;
5281 int err;
5282
5283 BT_DBG("%s", hdev->name);
5284
Johan Hedberg66593582014-07-09 12:59:14 +03005285 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005286 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005287 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5288 MGMT_STATUS_INVALID_PARAMS,
5289 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005290
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005291 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005292 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5293 MGMT_STATUS_INVALID_PARAMS,
5294 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005295
5296 hci_dev_lock(hdev);
5297
Johan Hedberg66593582014-07-09 12:59:14 +03005298 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005299 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005300 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005301 err = mgmt_cmd_complete(sk, hdev->id,
5302 MGMT_OP_ADD_DEVICE,
5303 MGMT_STATUS_INVALID_PARAMS,
5304 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005305 goto unlock;
5306 }
5307
5308 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5309 cp->addr.type);
5310 if (err)
5311 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005312
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005313 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005314
Johan Hedberg66593582014-07-09 12:59:14 +03005315 goto added;
5316 }
5317
Johan Hedberg85813a72015-10-21 18:02:59 +03005318 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005319
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005320 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005321 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005322 else if (cp->action == 0x01)
5323 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005324 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005325 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005326
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005327 /* Kernel internally uses conn_params with resolvable private
5328 * address, but Add Device allows only identity addresses.
5329 * Make sure it is enforced before calling
5330 * hci_conn_params_lookup.
5331 */
5332 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005333 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5334 MGMT_STATUS_INVALID_PARAMS,
5335 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005336 goto unlock;
5337 }
5338
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005339 /* If the connection parameters don't exist for this device,
5340 * they will be created and configured with defaults.
5341 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005342 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005343 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005344 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5345 MGMT_STATUS_FAILED, &cp->addr,
5346 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005347 goto unlock;
5348 }
5349
Johan Hedberg51d7a942015-11-11 08:11:18 +02005350 hci_update_background_scan(hdev);
5351
Johan Hedberg66593582014-07-09 12:59:14 +03005352added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005353 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5354
Johan Hedberg51d7a942015-11-11 08:11:18 +02005355 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5356 MGMT_STATUS_SUCCESS, &cp->addr,
5357 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005358
5359unlock:
5360 hci_dev_unlock(hdev);
5361 return err;
5362}
5363
Marcel Holtmann8afef092014-06-29 22:28:34 +02005364static void device_removed(struct sock *sk, struct hci_dev *hdev,
5365 bdaddr_t *bdaddr, u8 type)
5366{
5367 struct mgmt_ev_device_removed ev;
5368
5369 bacpy(&ev.addr.bdaddr, bdaddr);
5370 ev.addr.type = type;
5371
5372 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5373}
5374
Marcel Holtmann2faade52014-06-29 19:44:03 +02005375static int remove_device(struct sock *sk, struct hci_dev *hdev,
5376 void *data, u16 len)
5377{
5378 struct mgmt_cp_remove_device *cp = data;
5379 int err;
5380
5381 BT_DBG("%s", hdev->name);
5382
5383 hci_dev_lock(hdev);
5384
5385 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005386 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005387 u8 addr_type;
5388
Johan Hedberg66593582014-07-09 12:59:14 +03005389 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005390 err = mgmt_cmd_complete(sk, hdev->id,
5391 MGMT_OP_REMOVE_DEVICE,
5392 MGMT_STATUS_INVALID_PARAMS,
5393 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005394 goto unlock;
5395 }
5396
Johan Hedberg66593582014-07-09 12:59:14 +03005397 if (cp->addr.type == BDADDR_BREDR) {
5398 err = hci_bdaddr_list_del(&hdev->whitelist,
5399 &cp->addr.bdaddr,
5400 cp->addr.type);
5401 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005402 err = mgmt_cmd_complete(sk, hdev->id,
5403 MGMT_OP_REMOVE_DEVICE,
5404 MGMT_STATUS_INVALID_PARAMS,
5405 &cp->addr,
5406 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005407 goto unlock;
5408 }
5409
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005410 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005411
Johan Hedberg66593582014-07-09 12:59:14 +03005412 device_removed(sk, hdev, &cp->addr.bdaddr,
5413 cp->addr.type);
5414 goto complete;
5415 }
5416
Johan Hedberg85813a72015-10-21 18:02:59 +03005417 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005418
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005419 /* Kernel internally uses conn_params with resolvable private
5420 * address, but Remove Device allows only identity addresses.
5421 * Make sure it is enforced before calling
5422 * hci_conn_params_lookup.
5423 */
5424 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005425 err = mgmt_cmd_complete(sk, hdev->id,
5426 MGMT_OP_REMOVE_DEVICE,
5427 MGMT_STATUS_INVALID_PARAMS,
5428 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005429 goto unlock;
5430 }
5431
Johan Hedbergc71593d2014-07-02 17:37:28 +03005432 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5433 addr_type);
5434 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005435 err = mgmt_cmd_complete(sk, hdev->id,
5436 MGMT_OP_REMOVE_DEVICE,
5437 MGMT_STATUS_INVALID_PARAMS,
5438 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005439 goto unlock;
5440 }
5441
Johan Hedberg679d2b62015-10-16 10:07:52 +03005442 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5443 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005444 err = mgmt_cmd_complete(sk, hdev->id,
5445 MGMT_OP_REMOVE_DEVICE,
5446 MGMT_STATUS_INVALID_PARAMS,
5447 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005448 goto unlock;
5449 }
5450
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005451 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005452 list_del(&params->list);
5453 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005454 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005455
5456 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005457 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005458 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005459 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005460
Marcel Holtmann2faade52014-06-29 19:44:03 +02005461 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005462 err = mgmt_cmd_complete(sk, hdev->id,
5463 MGMT_OP_REMOVE_DEVICE,
5464 MGMT_STATUS_INVALID_PARAMS,
5465 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005466 goto unlock;
5467 }
5468
Johan Hedberg66593582014-07-09 12:59:14 +03005469 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5470 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5471 list_del(&b->list);
5472 kfree(b);
5473 }
5474
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005475 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005476
Johan Hedberg19de0822014-07-06 13:06:51 +03005477 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5478 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5479 continue;
5480 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005481 if (p->explicit_connect) {
5482 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5483 continue;
5484 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005485 list_del(&p->action);
5486 list_del(&p->list);
5487 kfree(p);
5488 }
5489
5490 BT_DBG("All LE connection parameters were removed");
5491
Johan Hedberg51d7a942015-11-11 08:11:18 +02005492 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005493 }
5494
Johan Hedberg66593582014-07-09 12:59:14 +03005495complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005496 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5497 MGMT_STATUS_SUCCESS, &cp->addr,
5498 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005499unlock:
5500 hci_dev_unlock(hdev);
5501 return err;
5502}
5503
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005504static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5505 u16 len)
5506{
5507 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005508 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5509 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005510 u16 param_count, expected_len;
5511 int i;
5512
5513 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005514 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5515 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005516
5517 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005518 if (param_count > max_param_count) {
5519 BT_ERR("load_conn_param: too big param_count value %u",
5520 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005521 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5522 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005523 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005524
5525 expected_len = sizeof(*cp) + param_count *
5526 sizeof(struct mgmt_conn_param);
5527 if (expected_len != len) {
5528 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5529 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005530 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5531 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005532 }
5533
5534 BT_DBG("%s param_count %u", hdev->name, param_count);
5535
5536 hci_dev_lock(hdev);
5537
5538 hci_conn_params_clear_disabled(hdev);
5539
5540 for (i = 0; i < param_count; i++) {
5541 struct mgmt_conn_param *param = &cp->params[i];
5542 struct hci_conn_params *hci_param;
5543 u16 min, max, latency, timeout;
5544 u8 addr_type;
5545
5546 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5547 param->addr.type);
5548
5549 if (param->addr.type == BDADDR_LE_PUBLIC) {
5550 addr_type = ADDR_LE_DEV_PUBLIC;
5551 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5552 addr_type = ADDR_LE_DEV_RANDOM;
5553 } else {
5554 BT_ERR("Ignoring invalid connection parameters");
5555 continue;
5556 }
5557
5558 min = le16_to_cpu(param->min_interval);
5559 max = le16_to_cpu(param->max_interval);
5560 latency = le16_to_cpu(param->latency);
5561 timeout = le16_to_cpu(param->timeout);
5562
5563 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5564 min, max, latency, timeout);
5565
5566 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5567 BT_ERR("Ignoring invalid connection parameters");
5568 continue;
5569 }
5570
5571 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5572 addr_type);
5573 if (!hci_param) {
5574 BT_ERR("Failed to add connection parameters");
5575 continue;
5576 }
5577
5578 hci_param->conn_min_interval = min;
5579 hci_param->conn_max_interval = max;
5580 hci_param->conn_latency = latency;
5581 hci_param->supervision_timeout = timeout;
5582 }
5583
5584 hci_dev_unlock(hdev);
5585
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005586 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5587 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005588}
5589
Marcel Holtmanndbece372014-07-04 18:11:55 +02005590static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5591 void *data, u16 len)
5592{
5593 struct mgmt_cp_set_external_config *cp = data;
5594 bool changed;
5595 int err;
5596
5597 BT_DBG("%s", hdev->name);
5598
5599 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005600 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5601 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005602
5603 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005604 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5605 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005606
5607 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005608 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5609 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005610
5611 hci_dev_lock(hdev);
5612
5613 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005614 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005615 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005616 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005617
5618 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5619 if (err < 0)
5620 goto unlock;
5621
5622 if (!changed)
5623 goto unlock;
5624
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005625 err = new_options(hdev, sk);
5626
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005627 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005628 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005629
Marcel Holtmann516018a2015-03-13 02:11:04 -07005630 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005631 hci_dev_set_flag(hdev, HCI_CONFIG);
5632 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005633
5634 queue_work(hdev->req_workqueue, &hdev->power_on);
5635 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005636 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005637 mgmt_index_added(hdev);
5638 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005639 }
5640
5641unlock:
5642 hci_dev_unlock(hdev);
5643 return err;
5644}
5645
Marcel Holtmann9713c172014-07-06 12:11:15 +02005646static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5647 void *data, u16 len)
5648{
5649 struct mgmt_cp_set_public_address *cp = data;
5650 bool changed;
5651 int err;
5652
5653 BT_DBG("%s", hdev->name);
5654
5655 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005656 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5657 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005658
5659 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005660 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5661 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005662
5663 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005664 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5665 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005666
5667 hci_dev_lock(hdev);
5668
5669 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5670 bacpy(&hdev->public_addr, &cp->bdaddr);
5671
5672 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5673 if (err < 0)
5674 goto unlock;
5675
5676 if (!changed)
5677 goto unlock;
5678
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005679 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005680 err = new_options(hdev, sk);
5681
5682 if (is_configured(hdev)) {
5683 mgmt_index_removed(hdev);
5684
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005685 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005686
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005687 hci_dev_set_flag(hdev, HCI_CONFIG);
5688 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005689
5690 queue_work(hdev->req_workqueue, &hdev->power_on);
5691 }
5692
5693unlock:
5694 hci_dev_unlock(hdev);
5695 return err;
5696}
5697
Marcel Holtmannbea41602015-03-14 22:43:17 -07005698static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5699 u8 data_len)
5700{
5701 eir[eir_len++] = sizeof(type) + data_len;
5702 eir[eir_len++] = type;
5703 memcpy(&eir[eir_len], data, data_len);
5704 eir_len += data_len;
5705
5706 return eir_len;
5707}
5708
Johan Hedberg40f66c02015-04-07 21:52:22 +03005709static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5710 u16 opcode, struct sk_buff *skb)
5711{
5712 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5713 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5714 u8 *h192, *r192, *h256, *r256;
5715 struct mgmt_pending_cmd *cmd;
5716 u16 eir_len;
5717 int err;
5718
5719 BT_DBG("%s status %u", hdev->name, status);
5720
5721 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5722 if (!cmd)
5723 return;
5724
5725 mgmt_cp = cmd->param;
5726
5727 if (status) {
5728 status = mgmt_status(status);
5729 eir_len = 0;
5730
5731 h192 = NULL;
5732 r192 = NULL;
5733 h256 = NULL;
5734 r256 = NULL;
5735 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5736 struct hci_rp_read_local_oob_data *rp;
5737
5738 if (skb->len != sizeof(*rp)) {
5739 status = MGMT_STATUS_FAILED;
5740 eir_len = 0;
5741 } else {
5742 status = MGMT_STATUS_SUCCESS;
5743 rp = (void *)skb->data;
5744
5745 eir_len = 5 + 18 + 18;
5746 h192 = rp->hash;
5747 r192 = rp->rand;
5748 h256 = NULL;
5749 r256 = NULL;
5750 }
5751 } else {
5752 struct hci_rp_read_local_oob_ext_data *rp;
5753
5754 if (skb->len != sizeof(*rp)) {
5755 status = MGMT_STATUS_FAILED;
5756 eir_len = 0;
5757 } else {
5758 status = MGMT_STATUS_SUCCESS;
5759 rp = (void *)skb->data;
5760
5761 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5762 eir_len = 5 + 18 + 18;
5763 h192 = NULL;
5764 r192 = NULL;
5765 } else {
5766 eir_len = 5 + 18 + 18 + 18 + 18;
5767 h192 = rp->hash192;
5768 r192 = rp->rand192;
5769 }
5770
5771 h256 = rp->hash256;
5772 r256 = rp->rand256;
5773 }
5774 }
5775
5776 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5777 if (!mgmt_rp)
5778 goto done;
5779
5780 if (status)
5781 goto send_rsp;
5782
5783 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5784 hdev->dev_class, 3);
5785
5786 if (h192 && r192) {
5787 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5788 EIR_SSP_HASH_C192, h192, 16);
5789 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5790 EIR_SSP_RAND_R192, r192, 16);
5791 }
5792
5793 if (h256 && r256) {
5794 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5795 EIR_SSP_HASH_C256, h256, 16);
5796 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5797 EIR_SSP_RAND_R256, r256, 16);
5798 }
5799
5800send_rsp:
5801 mgmt_rp->type = mgmt_cp->type;
5802 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5803
5804 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5805 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5806 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5807 if (err < 0 || status)
5808 goto done;
5809
5810 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5811
5812 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5813 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5814 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5815done:
5816 kfree(mgmt_rp);
5817 mgmt_pending_remove(cmd);
5818}
5819
5820static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5821 struct mgmt_cp_read_local_oob_ext_data *cp)
5822{
5823 struct mgmt_pending_cmd *cmd;
5824 struct hci_request req;
5825 int err;
5826
5827 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5828 cp, sizeof(*cp));
5829 if (!cmd)
5830 return -ENOMEM;
5831
5832 hci_req_init(&req, hdev);
5833
5834 if (bredr_sc_enabled(hdev))
5835 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5836 else
5837 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5838
5839 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5840 if (err < 0) {
5841 mgmt_pending_remove(cmd);
5842 return err;
5843 }
5844
5845 return 0;
5846}
5847
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005848static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5849 void *data, u16 data_len)
5850{
5851 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5852 struct mgmt_rp_read_local_oob_ext_data *rp;
5853 size_t rp_len;
5854 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005855 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005856 int err;
5857
5858 BT_DBG("%s", hdev->name);
5859
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005860 if (hdev_is_powered(hdev)) {
5861 switch (cp->type) {
5862 case BIT(BDADDR_BREDR):
5863 status = mgmt_bredr_support(hdev);
5864 if (status)
5865 eir_len = 0;
5866 else
5867 eir_len = 5;
5868 break;
5869 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5870 status = mgmt_le_support(hdev);
5871 if (status)
5872 eir_len = 0;
5873 else
5874 eir_len = 9 + 3 + 18 + 18 + 3;
5875 break;
5876 default:
5877 status = MGMT_STATUS_INVALID_PARAMS;
5878 eir_len = 0;
5879 break;
5880 }
5881 } else {
5882 status = MGMT_STATUS_NOT_POWERED;
5883 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005884 }
5885
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005886 rp_len = sizeof(*rp) + eir_len;
5887 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005888 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005889 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005890
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005891 if (status)
5892 goto complete;
5893
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005894 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005895
5896 eir_len = 0;
5897 switch (cp->type) {
5898 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005899 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5900 err = read_local_ssp_oob_req(hdev, sk, cp);
5901 hci_dev_unlock(hdev);
5902 if (!err)
5903 goto done;
5904
5905 status = MGMT_STATUS_FAILED;
5906 goto complete;
5907 } else {
5908 eir_len = eir_append_data(rp->eir, eir_len,
5909 EIR_CLASS_OF_DEV,
5910 hdev->dev_class, 3);
5911 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005912 break;
5913 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005914 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5915 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005916 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005917 status = MGMT_STATUS_FAILED;
5918 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005919 }
5920
Marcel Holtmanne2135682015-04-02 12:00:58 -07005921 /* This should return the active RPA, but since the RPA
5922 * is only programmed on demand, it is really hard to fill
5923 * this in at the moment. For now disallow retrieving
5924 * local out-of-band data when privacy is in use.
5925 *
5926 * Returning the identity address will not help here since
5927 * pairing happens before the identity resolving key is
5928 * known and thus the connection establishment happens
5929 * based on the RPA and not the identity address.
5930 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005931 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005932 hci_dev_unlock(hdev);
5933 status = MGMT_STATUS_REJECTED;
5934 goto complete;
5935 }
5936
5937 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5938 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5939 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5940 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005941 memcpy(addr, &hdev->static_addr, 6);
5942 addr[6] = 0x01;
5943 } else {
5944 memcpy(addr, &hdev->bdaddr, 6);
5945 addr[6] = 0x00;
5946 }
5947
5948 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5949 addr, sizeof(addr));
5950
5951 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5952 role = 0x02;
5953 else
5954 role = 0x01;
5955
5956 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5957 &role, sizeof(role));
5958
Marcel Holtmann5082a592015-03-16 12:39:00 -07005959 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5960 eir_len = eir_append_data(rp->eir, eir_len,
5961 EIR_LE_SC_CONFIRM,
5962 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005963
Marcel Holtmann5082a592015-03-16 12:39:00 -07005964 eir_len = eir_append_data(rp->eir, eir_len,
5965 EIR_LE_SC_RANDOM,
5966 rand, sizeof(rand));
5967 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005968
Johan Hedbergf2252572015-11-18 12:49:20 +02005969 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005970
5971 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5972 flags |= LE_AD_NO_BREDR;
5973
5974 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5975 &flags, sizeof(flags));
5976 break;
5977 }
5978
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005979 hci_dev_unlock(hdev);
5980
Marcel Holtmann72000df2015-03-16 16:11:21 -07005981 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5982
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005983 status = MGMT_STATUS_SUCCESS;
5984
5985complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005986 rp->type = cp->type;
5987 rp->eir_len = cpu_to_le16(eir_len);
5988
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005989 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005990 status, rp, sizeof(*rp) + eir_len);
5991 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005992 goto done;
5993
5994 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5995 rp, sizeof(*rp) + eir_len,
5996 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005997
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005998done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005999 kfree(rp);
6000
6001 return err;
6002}
6003
Arman Uguray089fa8c2015-03-25 18:53:45 -07006004static u32 get_supported_adv_flags(struct hci_dev *hdev)
6005{
6006 u32 flags = 0;
6007
6008 flags |= MGMT_ADV_FLAG_CONNECTABLE;
6009 flags |= MGMT_ADV_FLAG_DISCOV;
6010 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
6011 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
6012
6013 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
6014 flags |= MGMT_ADV_FLAG_TX_POWER;
6015
6016 return flags;
6017}
6018
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006019static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6020 void *data, u16 data_len)
6021{
6022 struct mgmt_rp_read_adv_features *rp;
6023 size_t rp_len;
Florian Grandel286e0c82015-06-18 03:16:38 +02006024 int err, i;
Arman Uguray24b4f382015-03-23 15:57:12 -07006025 bool instance;
Florian Grandel286e0c82015-06-18 03:16:38 +02006026 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006027 u32 supported_flags;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006028
6029 BT_DBG("%s", hdev->name);
6030
Arman Uguray089fa8c2015-03-25 18:53:45 -07006031 if (!lmp_le_capable(hdev))
6032 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6033 MGMT_STATUS_REJECTED);
6034
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006035 hci_dev_lock(hdev);
6036
6037 rp_len = sizeof(*rp);
Arman Uguray24b4f382015-03-23 15:57:12 -07006038
Arman Uguray24b4f382015-03-23 15:57:12 -07006039 instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
6040 if (instance)
Florian Grandel286e0c82015-06-18 03:16:38 +02006041 rp_len += hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006042
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006043 rp = kmalloc(rp_len, GFP_ATOMIC);
6044 if (!rp) {
6045 hci_dev_unlock(hdev);
6046 return -ENOMEM;
6047 }
6048
Arman Uguray089fa8c2015-03-25 18:53:45 -07006049 supported_flags = get_supported_adv_flags(hdev);
6050
6051 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006052 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6053 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02006054 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Arman Uguray24b4f382015-03-23 15:57:12 -07006055
Arman Uguray24b4f382015-03-23 15:57:12 -07006056 if (instance) {
Florian Grandel286e0c82015-06-18 03:16:38 +02006057 i = 0;
6058 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
6059 if (i >= hdev->adv_instance_cnt)
6060 break;
6061
6062 rp->instance[i] = adv_instance->instance;
6063 i++;
6064 }
6065 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07006066 } else {
6067 rp->num_instances = 0;
6068 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006069
6070 hci_dev_unlock(hdev);
6071
6072 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6073 MGMT_STATUS_SUCCESS, rp, rp_len);
6074
6075 kfree(rp);
6076
6077 return err;
6078}
6079
Arman Uguray4117ed72015-03-23 15:57:14 -07006080static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006081 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07006082{
Arman Uguray4117ed72015-03-23 15:57:14 -07006083 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006084 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07006085 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07006086 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07006087
Marcel Holtmann31a32482015-11-19 16:16:42 +01006088 if (is_adv_data) {
6089 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6090 MGMT_ADV_FLAG_LIMITED_DISCOV |
6091 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
6092 flags_managed = true;
6093 max_len -= 3;
6094 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006095
Marcel Holtmann31a32482015-11-19 16:16:42 +01006096 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
6097 tx_power_managed = true;
6098 max_len -= 3;
6099 }
Arman Uguray5507e352015-03-25 18:53:44 -07006100 }
6101
Arman Uguray4117ed72015-03-23 15:57:14 -07006102 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006103 return false;
6104
Arman Uguray4117ed72015-03-23 15:57:14 -07006105 /* Make sure that the data is correctly formatted. */
6106 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6107 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006108
Arman Ugurayb44133f2015-03-25 18:53:41 -07006109 if (flags_managed && data[i + 1] == EIR_FLAGS)
6110 return false;
6111
Arman Uguray5507e352015-03-25 18:53:44 -07006112 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
6113 return false;
6114
Arman Uguray24b4f382015-03-23 15:57:12 -07006115 /* If the current field length would exceed the total data
6116 * length, then it's invalid.
6117 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006118 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006119 return false;
6120 }
6121
6122 return true;
6123}
6124
Arman Uguray24b4f382015-03-23 15:57:12 -07006125static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6126 u16 opcode)
6127{
6128 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006129 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006130 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006131 struct adv_info *adv_instance, *n;
6132 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006133
6134 BT_DBG("status %d", status);
6135
6136 hci_dev_lock(hdev);
6137
6138 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6139
Florian Grandelfffd38b2015-06-18 03:16:47 +02006140 if (status)
Arman Uguray24b4f382015-03-23 15:57:12 -07006141 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006142
6143 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6144 if (!adv_instance->pending)
6145 continue;
6146
6147 if (!status) {
6148 adv_instance->pending = false;
6149 continue;
6150 }
6151
6152 instance = adv_instance->instance;
6153
6154 if (hdev->cur_adv_instance == instance)
6155 cancel_adv_timeout(hdev);
6156
6157 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006158 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006159 }
6160
6161 if (!cmd)
6162 goto unlock;
6163
Florian Grandelfffd38b2015-06-18 03:16:47 +02006164 cp = cmd->param;
6165 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006166
6167 if (status)
6168 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6169 mgmt_status(status));
6170 else
6171 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6172 mgmt_status(status), &rp, sizeof(rp));
6173
6174 mgmt_pending_remove(cmd);
6175
6176unlock:
6177 hci_dev_unlock(hdev);
6178}
6179
6180static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6181 void *data, u16 data_len)
6182{
6183 struct mgmt_cp_add_advertising *cp = data;
6184 struct mgmt_rp_add_advertising rp;
6185 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006186 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006187 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006188 u16 timeout, duration;
6189 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6190 u8 schedule_instance = 0;
6191 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006192 int err;
6193 struct mgmt_pending_cmd *cmd;
6194 struct hci_request req;
6195
6196 BT_DBG("%s", hdev->name);
6197
6198 status = mgmt_le_support(hdev);
6199 if (status)
6200 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6201 status);
6202
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006203 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6204 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6205 MGMT_STATUS_INVALID_PARAMS);
6206
Arman Uguray24b4f382015-03-23 15:57:12 -07006207 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006208 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006209 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006210
Florian Grandelfffd38b2015-06-18 03:16:47 +02006211 /* The current implementation only supports a subset of the specified
6212 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006213 */
6214 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006215 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006216 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6217 MGMT_STATUS_INVALID_PARAMS);
6218
6219 hci_dev_lock(hdev);
6220
Arman Uguray912098a2015-03-23 15:57:15 -07006221 if (timeout && !hdev_is_powered(hdev)) {
6222 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6223 MGMT_STATUS_REJECTED);
6224 goto unlock;
6225 }
6226
Arman Uguray24b4f382015-03-23 15:57:12 -07006227 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006228 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006229 pending_find(MGMT_OP_SET_LE, hdev)) {
6230 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6231 MGMT_STATUS_BUSY);
6232 goto unlock;
6233 }
6234
Arman Ugurayb44133f2015-03-25 18:53:41 -07006235 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006236 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006237 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006238 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6239 MGMT_STATUS_INVALID_PARAMS);
6240 goto unlock;
6241 }
6242
Florian Grandelfffd38b2015-06-18 03:16:47 +02006243 err = hci_add_adv_instance(hdev, cp->instance, flags,
6244 cp->adv_data_len, cp->data,
6245 cp->scan_rsp_len,
6246 cp->data + cp->adv_data_len,
6247 timeout, duration);
6248 if (err < 0) {
6249 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6250 MGMT_STATUS_FAILED);
6251 goto unlock;
6252 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006253
Florian Grandelfffd38b2015-06-18 03:16:47 +02006254 /* Only trigger an advertising added event if a new instance was
6255 * actually added.
6256 */
6257 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006258 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006259
Florian Grandelfffd38b2015-06-18 03:16:47 +02006260 hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);
Arman Uguray24b4f382015-03-23 15:57:12 -07006261
Florian Grandelfffd38b2015-06-18 03:16:47 +02006262 if (hdev->cur_adv_instance == cp->instance) {
6263 /* If the currently advertised instance is being changed then
6264 * cancel the current advertising and schedule the next
6265 * instance. If there is only one instance then the overridden
6266 * advertising data will be visible right away.
6267 */
6268 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006269
Florian Grandelfffd38b2015-06-18 03:16:47 +02006270 next_instance = hci_get_next_instance(hdev, cp->instance);
6271 if (next_instance)
6272 schedule_instance = next_instance->instance;
6273 } else if (!hdev->adv_instance_timeout) {
6274 /* Immediately advertise the new instance if no other
6275 * instance is currently being advertised.
6276 */
6277 schedule_instance = cp->instance;
6278 }
Arman Uguray912098a2015-03-23 15:57:15 -07006279
Florian Grandelfffd38b2015-06-18 03:16:47 +02006280 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6281 * there is no instance to be advertised then we have no HCI
6282 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006283 */
6284 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006285 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6286 !schedule_instance) {
6287 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006288 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6289 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6290 goto unlock;
6291 }
6292
6293 /* We're good to go, update advertising data, parameters, and start
6294 * advertising.
6295 */
6296 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6297 data_len);
6298 if (!cmd) {
6299 err = -ENOMEM;
6300 goto unlock;
6301 }
6302
6303 hci_req_init(&req, hdev);
6304
Johan Hedbergf2252572015-11-18 12:49:20 +02006305 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006306
Florian Grandelfffd38b2015-06-18 03:16:47 +02006307 if (!err)
6308 err = hci_req_run(&req, add_advertising_complete);
6309
Arman Uguray24b4f382015-03-23 15:57:12 -07006310 if (err < 0)
6311 mgmt_pending_remove(cmd);
6312
6313unlock:
6314 hci_dev_unlock(hdev);
6315
6316 return err;
6317}
6318
Arman Ugurayda9293352015-03-23 15:57:13 -07006319static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6320 u16 opcode)
6321{
6322 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006323 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006324 struct mgmt_rp_remove_advertising rp;
6325
6326 BT_DBG("status %d", status);
6327
6328 hci_dev_lock(hdev);
6329
6330 /* A failure status here only means that we failed to disable
6331 * advertising. Otherwise, the advertising instance has been removed,
6332 * so report success.
6333 */
6334 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6335 if (!cmd)
6336 goto unlock;
6337
Florian Grandel01948332015-06-18 03:16:48 +02006338 cp = cmd->param;
6339 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006340
6341 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6342 &rp, sizeof(rp));
6343 mgmt_pending_remove(cmd);
6344
6345unlock:
6346 hci_dev_unlock(hdev);
6347}
6348
6349static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6350 void *data, u16 data_len)
6351{
6352 struct mgmt_cp_remove_advertising *cp = data;
6353 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006354 struct mgmt_pending_cmd *cmd;
6355 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006356 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006357
6358 BT_DBG("%s", hdev->name);
6359
Arman Ugurayda9293352015-03-23 15:57:13 -07006360 hci_dev_lock(hdev);
6361
Johan Hedberg952497b2015-06-18 21:05:31 +03006362 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006363 err = mgmt_cmd_status(sk, hdev->id,
6364 MGMT_OP_REMOVE_ADVERTISING,
6365 MGMT_STATUS_INVALID_PARAMS);
6366 goto unlock;
6367 }
6368
Arman Ugurayda9293352015-03-23 15:57:13 -07006369 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6370 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6371 pending_find(MGMT_OP_SET_LE, hdev)) {
6372 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6373 MGMT_STATUS_BUSY);
6374 goto unlock;
6375 }
6376
6377 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
6378 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6379 MGMT_STATUS_INVALID_PARAMS);
6380 goto unlock;
6381 }
6382
Florian Grandel01948332015-06-18 03:16:48 +02006383 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006384
Johan Hedbergf2252572015-11-18 12:49:20 +02006385 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006386
Florian Grandel01948332015-06-18 03:16:48 +02006387 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006388 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006389
Florian Grandel01948332015-06-18 03:16:48 +02006390 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6391 * flag is set or the device isn't powered then we have no HCI
6392 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006393 */
Florian Grandel01948332015-06-18 03:16:48 +02006394 if (skb_queue_empty(&req.cmd_q) ||
6395 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006396 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006397 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006398 err = mgmt_cmd_complete(sk, hdev->id,
6399 MGMT_OP_REMOVE_ADVERTISING,
6400 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6401 goto unlock;
6402 }
6403
6404 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6405 data_len);
6406 if (!cmd) {
6407 err = -ENOMEM;
6408 goto unlock;
6409 }
6410
Arman Ugurayda9293352015-03-23 15:57:13 -07006411 err = hci_req_run(&req, remove_advertising_complete);
6412 if (err < 0)
6413 mgmt_pending_remove(cmd);
6414
6415unlock:
6416 hci_dev_unlock(hdev);
6417
6418 return err;
6419}
6420
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006421static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6422{
6423 u8 max_len = HCI_MAX_AD_LENGTH;
6424
6425 if (is_adv_data) {
6426 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6427 MGMT_ADV_FLAG_LIMITED_DISCOV |
6428 MGMT_ADV_FLAG_MANAGED_FLAGS))
6429 max_len -= 3;
6430
6431 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6432 max_len -= 3;
6433 }
6434
6435 return max_len;
6436}
6437
6438static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6439 void *data, u16 data_len)
6440{
6441 struct mgmt_cp_get_adv_size_info *cp = data;
6442 struct mgmt_rp_get_adv_size_info rp;
6443 u32 flags, supported_flags;
6444 int err;
6445
6446 BT_DBG("%s", hdev->name);
6447
6448 if (!lmp_le_capable(hdev))
6449 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6450 MGMT_STATUS_REJECTED);
6451
6452 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6453 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6454 MGMT_STATUS_INVALID_PARAMS);
6455
6456 flags = __le32_to_cpu(cp->flags);
6457
6458 /* The current implementation only supports a subset of the specified
6459 * flags.
6460 */
6461 supported_flags = get_supported_adv_flags(hdev);
6462 if (flags & ~supported_flags)
6463 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6464 MGMT_STATUS_INVALID_PARAMS);
6465
6466 rp.instance = cp->instance;
6467 rp.flags = cp->flags;
6468 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6469 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6470
6471 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6472 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6473
6474 return err;
6475}
6476
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006477static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006478 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006479 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006480 HCI_MGMT_NO_HDEV |
6481 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006482 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006483 HCI_MGMT_NO_HDEV |
6484 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006485 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006486 HCI_MGMT_NO_HDEV |
6487 HCI_MGMT_UNTRUSTED },
6488 { read_controller_info, MGMT_READ_INFO_SIZE,
6489 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006490 { set_powered, MGMT_SETTING_SIZE },
6491 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6492 { set_connectable, MGMT_SETTING_SIZE },
6493 { set_fast_connectable, MGMT_SETTING_SIZE },
6494 { set_bondable, MGMT_SETTING_SIZE },
6495 { set_link_security, MGMT_SETTING_SIZE },
6496 { set_ssp, MGMT_SETTING_SIZE },
6497 { set_hs, MGMT_SETTING_SIZE },
6498 { set_le, MGMT_SETTING_SIZE },
6499 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6500 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6501 { add_uuid, MGMT_ADD_UUID_SIZE },
6502 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006503 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6504 HCI_MGMT_VAR_LEN },
6505 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6506 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006507 { disconnect, MGMT_DISCONNECT_SIZE },
6508 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6509 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6510 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6511 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6512 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6513 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6514 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6515 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6516 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6517 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6518 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006519 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6520 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6521 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006522 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6523 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6524 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6525 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6526 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6527 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6528 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6529 { set_advertising, MGMT_SETTING_SIZE },
6530 { set_bredr, MGMT_SETTING_SIZE },
6531 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6532 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6533 { set_secure_conn, MGMT_SETTING_SIZE },
6534 { set_debug_keys, MGMT_SETTING_SIZE },
6535 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006536 { load_irks, MGMT_LOAD_IRKS_SIZE,
6537 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006538 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6539 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6540 { add_device, MGMT_ADD_DEVICE_SIZE },
6541 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006542 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6543 HCI_MGMT_VAR_LEN },
6544 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006545 HCI_MGMT_NO_HDEV |
6546 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006547 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006548 HCI_MGMT_UNCONFIGURED |
6549 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006550 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6551 HCI_MGMT_UNCONFIGURED },
6552 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6553 HCI_MGMT_UNCONFIGURED },
6554 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6555 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006556 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006557 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006558 HCI_MGMT_NO_HDEV |
6559 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006560 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006561 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6562 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006563 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006564 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006565};
6566
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006567void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006568{
Marcel Holtmannced85542015-03-14 19:27:56 -07006569 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006570
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006571 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6572 return;
6573
Marcel Holtmannf9207332015-03-14 19:27:55 -07006574 switch (hdev->dev_type) {
6575 case HCI_BREDR:
6576 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6577 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6578 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006579 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006580 } else {
6581 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6582 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006583 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006584 }
6585 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006586 case HCI_AMP:
6587 ev.type = 0x02;
6588 break;
6589 default:
6590 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006591 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006592
6593 ev.bus = hdev->bus;
6594
6595 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6596 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006597}
6598
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006599void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006600{
Marcel Holtmannced85542015-03-14 19:27:56 -07006601 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006602 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006603
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006604 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6605 return;
6606
Marcel Holtmannf9207332015-03-14 19:27:55 -07006607 switch (hdev->dev_type) {
6608 case HCI_BREDR:
6609 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006610
Marcel Holtmannf9207332015-03-14 19:27:55 -07006611 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6612 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6613 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006614 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006615 } else {
6616 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6617 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006618 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006619 }
6620 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006621 case HCI_AMP:
6622 ev.type = 0x02;
6623 break;
6624 default:
6625 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006626 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006627
6628 ev.bus = hdev->bus;
6629
6630 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6631 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006632}
6633
Andre Guedes6046dc32014-02-26 20:21:51 -03006634/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006635static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006636{
6637 struct hci_conn_params *p;
6638
6639 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006640 /* Needed for AUTO_OFF case where might not "really"
6641 * have been powered off.
6642 */
6643 list_del_init(&p->action);
6644
6645 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006646 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006647 case HCI_AUTO_CONN_ALWAYS:
6648 list_add(&p->action, &hdev->pend_le_conns);
6649 break;
6650 case HCI_AUTO_CONN_REPORT:
6651 list_add(&p->action, &hdev->pend_le_reports);
6652 break;
6653 default:
6654 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006655 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006656 }
6657}
6658
Marcel Holtmann1904a852015-01-11 13:50:44 -08006659static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006660{
6661 struct cmd_lookup match = { NULL, hdev };
6662
6663 BT_DBG("status 0x%02x", status);
6664
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006665 if (!status) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006666 restart_le_actions(hdev);
6667 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006668 }
6669
Johan Hedberg229ab392013-03-15 17:06:53 -05006670 hci_dev_lock(hdev);
6671
6672 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6673
6674 new_settings(hdev, match.sk);
6675
6676 hci_dev_unlock(hdev);
6677
6678 if (match.sk)
6679 sock_put(match.sk);
6680}
6681
Johan Hedberg70da6242013-03-15 17:06:51 -05006682static int powered_update_hci(struct hci_dev *hdev)
6683{
Johan Hedberg890ea892013-03-15 17:06:52 -05006684 struct hci_request req;
Florian Grandel320b3bf2015-06-18 03:16:49 +02006685 struct adv_info *adv_instance;
Johan Hedberg70da6242013-03-15 17:06:51 -05006686 u8 link_sec;
6687
Johan Hedberg890ea892013-03-15 17:06:52 -05006688 hci_req_init(&req, hdev);
6689
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006690 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006691 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006692 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006693
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006694 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006695
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006696 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6697 u8 support = 0x01;
6698
6699 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6700 sizeof(support), &support);
6701 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006702 }
6703
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006704 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006705 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006706 struct hci_cp_write_le_host_supported cp;
6707
Marcel Holtmann32226e42014-07-24 20:04:16 +02006708 cp.le = 0x01;
6709 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006710
6711 /* Check first if we already have the right
6712 * host state (host features set)
6713 */
6714 if (cp.le != lmp_host_le_capable(hdev) ||
6715 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006716 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6717 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006718 }
6719
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006720 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006721 /* Make sure the controller has a good default for
6722 * advertising data. This also applies to the case
6723 * where BR/EDR was toggled during the AUTO_OFF phase.
6724 */
Florian Grandel320b3bf2015-06-18 03:16:49 +02006725 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
6726 (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6727 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
Johan Hedbergf2252572015-11-18 12:49:20 +02006728 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
6729 __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006730 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006731
Florian Grandel320b3bf2015-06-18 03:16:49 +02006732 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6733 hdev->cur_adv_instance == 0x00 &&
6734 !list_empty(&hdev->adv_instances)) {
6735 adv_instance = list_first_entry(&hdev->adv_instances,
6736 struct adv_info, list);
6737 hdev->cur_adv_instance = adv_instance->instance;
6738 }
6739
6740 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergf2252572015-11-18 12:49:20 +02006741 __hci_req_enable_advertising(&req);
Florian Grandel320b3bf2015-06-18 03:16:49 +02006742 else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
6743 hdev->cur_adv_instance)
Johan Hedbergf2252572015-11-18 12:49:20 +02006744 __hci_req_schedule_adv_instance(&req,
6745 hdev->cur_adv_instance,
6746 true);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006747 }
6748
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006749 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006750 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006751 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6752 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006753
6754 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006755 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006756 write_fast_connectable(&req, true);
6757 else
6758 write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02006759 __hci_req_update_scan(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02006760 __hci_req_update_class(&req);
Johan Hedberg00cf5042015-11-25 16:15:41 +02006761 __hci_req_update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006762 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006763 }
6764
Johan Hedberg229ab392013-03-15 17:06:53 -05006765 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006766}
6767
Johan Hedberg744cf192011-11-08 20:40:14 +02006768int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006769{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006770 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006771 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006772 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006773
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006774 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006775 return 0;
6776
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006777 if (powered) {
Andrzej Kaczmareke59a5542015-11-22 21:42:21 +01006778 /* Register the available SMP channels (BR/EDR and LE) only
6779 * when successfully powering on the controller. This late
6780 * registration is required so that LE SMP can clearly
6781 * decide if the public address or static address is used.
6782 */
6783 smp_register(hdev);
6784
Johan Hedberg229ab392013-03-15 17:06:53 -05006785 if (powered_update_hci(hdev) == 0)
6786 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006787
Johan Hedberg229ab392013-03-15 17:06:53 -05006788 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6789 &match);
6790 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006791 }
6792
Johan Hedberg229ab392013-03-15 17:06:53 -05006793 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006794
6795 /* If the power off is because of hdev unregistration let
6796 * use the appropriate INVALID_INDEX status. Otherwise use
6797 * NOT_POWERED. We cover both scenarios here since later in
6798 * mgmt_index_removed() any hci_conn callbacks will have already
6799 * been triggered, potentially causing misleading DISCONNECTED
6800 * status responses.
6801 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006802 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006803 status = MGMT_STATUS_INVALID_INDEX;
6804 else
6805 status = MGMT_STATUS_NOT_POWERED;
6806
6807 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006808
6809 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006810 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6811 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006812
6813new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006814 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006815
6816 if (match.sk)
6817 sock_put(match.sk);
6818
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006819 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006820}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006821
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006822void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006823{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006824 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006825 u8 status;
6826
Johan Hedberg333ae952015-03-17 13:48:47 +02006827 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006828 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006829 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006830
6831 if (err == -ERFKILL)
6832 status = MGMT_STATUS_RFKILLED;
6833 else
6834 status = MGMT_STATUS_FAILED;
6835
Johan Hedberga69e8372015-03-06 21:08:53 +02006836 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006837
6838 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006839}
6840
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006841void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6842 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006843{
Johan Hedberg86742e12011-11-07 23:13:38 +02006844 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006845
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006846 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006847
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006848 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006849 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006850 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006851 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006852 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006853 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006854
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006855 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006856}
Johan Hedbergf7520542011-01-20 12:34:39 +02006857
Johan Hedbergd7b25452014-05-23 13:19:53 +03006858static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6859{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006860 switch (ltk->type) {
6861 case SMP_LTK:
6862 case SMP_LTK_SLAVE:
6863 if (ltk->authenticated)
6864 return MGMT_LTK_AUTHENTICATED;
6865 return MGMT_LTK_UNAUTHENTICATED;
6866 case SMP_LTK_P256:
6867 if (ltk->authenticated)
6868 return MGMT_LTK_P256_AUTH;
6869 return MGMT_LTK_P256_UNAUTH;
6870 case SMP_LTK_P256_DEBUG:
6871 return MGMT_LTK_P256_DEBUG;
6872 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006873
6874 return MGMT_LTK_UNAUTHENTICATED;
6875}
6876
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006877void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006878{
6879 struct mgmt_ev_new_long_term_key ev;
6880
6881 memset(&ev, 0, sizeof(ev));
6882
Marcel Holtmann5192d302014-02-19 17:11:58 -08006883 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006884 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006885 * to store long term keys. Their addresses will change the
6886 * next time around.
6887 *
6888 * Only when a remote device provides an identity address
6889 * make sure the long term key is stored. If the remote
6890 * identity is known, the long term keys are internally
6891 * mapped to the identity address. So allow static random
6892 * and public addresses here.
6893 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006894 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6895 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6896 ev.store_hint = 0x00;
6897 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006898 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006899
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006900 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006901 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006902 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006903 ev.key.enc_size = key->enc_size;
6904 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006905 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006906
Johan Hedberg2ceba532014-06-16 19:25:16 +03006907 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006908 ev.key.master = 1;
6909
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006910 /* Make sure we copy only the significant bytes based on the
6911 * encryption key size, and set the rest of the value to zeroes.
6912 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006913 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006914 memset(ev.key.val + key->enc_size, 0,
6915 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006916
Marcel Holtmann083368f2013-10-15 14:26:29 -07006917 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006918}
6919
Johan Hedbergcad20c22015-10-12 13:36:19 +02006920void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006921{
6922 struct mgmt_ev_new_irk ev;
6923
6924 memset(&ev, 0, sizeof(ev));
6925
Johan Hedbergcad20c22015-10-12 13:36:19 +02006926 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006927
Johan Hedberg95fbac82014-02-19 15:18:31 +02006928 bacpy(&ev.rpa, &irk->rpa);
6929 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6930 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6931 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6932
6933 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6934}
6935
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006936void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6937 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006938{
6939 struct mgmt_ev_new_csrk ev;
6940
6941 memset(&ev, 0, sizeof(ev));
6942
6943 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006944 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006945 * to store signature resolving keys. Their addresses will change
6946 * the next time around.
6947 *
6948 * Only when a remote device provides an identity address
6949 * make sure the signature resolving key is stored. So allow
6950 * static random and public addresses here.
6951 */
6952 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6953 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6954 ev.store_hint = 0x00;
6955 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006956 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006957
6958 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6959 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006960 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006961 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6962
6963 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6964}
6965
Andre Guedesffb5a8272014-07-01 18:10:11 -03006966void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006967 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6968 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006969{
6970 struct mgmt_ev_new_conn_param ev;
6971
Johan Hedbergc103aea2014-07-02 17:37:34 +03006972 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6973 return;
6974
Andre Guedesffb5a8272014-07-01 18:10:11 -03006975 memset(&ev, 0, sizeof(ev));
6976 bacpy(&ev.addr.bdaddr, bdaddr);
6977 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006978 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006979 ev.min_interval = cpu_to_le16(min_interval);
6980 ev.max_interval = cpu_to_le16(max_interval);
6981 ev.latency = cpu_to_le16(latency);
6982 ev.timeout = cpu_to_le16(timeout);
6983
6984 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6985}
6986
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006987void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6988 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006989{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006990 char buf[512];
6991 struct mgmt_ev_device_connected *ev = (void *) buf;
6992 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006993
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006994 bacpy(&ev->addr.bdaddr, &conn->dst);
6995 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006996
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006997 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006998
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006999 /* We must ensure that the EIR Data fields are ordered and
7000 * unique. Keep it simple for now and avoid the problem by not
7001 * adding any BR/EDR data to the LE adv.
7002 */
7003 if (conn->le_adv_data_len > 0) {
7004 memcpy(&ev->eir[eir_len],
7005 conn->le_adv_data, conn->le_adv_data_len);
7006 eir_len = conn->le_adv_data_len;
7007 } else {
7008 if (name_len > 0)
7009 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7010 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007011
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007012 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007013 eir_len = eir_append_data(ev->eir, eir_len,
7014 EIR_CLASS_OF_DEV,
7015 conn->dev_class, 3);
7016 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007017
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007018 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007019
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007020 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7021 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007022}
7023
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007024static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007025{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007026 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007027
Johan Hedbergf5818c22014-12-05 13:36:02 +02007028 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007029
7030 *sk = cmd->sk;
7031 sock_hold(*sk);
7032
Johan Hedberga664b5b2011-02-19 12:06:02 -03007033 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007034}
7035
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007036static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007037{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007038 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007039 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007040
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007041 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7042
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007043 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007044 mgmt_pending_remove(cmd);
7045}
7046
Johan Hedberg84c61d92014-08-01 11:13:30 +03007047bool mgmt_powering_down(struct hci_dev *hdev)
7048{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007049 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007050 struct mgmt_mode *cp;
7051
Johan Hedberg333ae952015-03-17 13:48:47 +02007052 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007053 if (!cmd)
7054 return false;
7055
7056 cp = cmd->param;
7057 if (!cp->val)
7058 return true;
7059
7060 return false;
7061}
7062
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007063void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007064 u8 link_type, u8 addr_type, u8 reason,
7065 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007066{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007067 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007068 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007069
Johan Hedberg84c61d92014-08-01 11:13:30 +03007070 /* The connection is still in hci_conn_hash so test for 1
7071 * instead of 0 to know if this is the last one.
7072 */
7073 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7074 cancel_delayed_work(&hdev->power_off);
7075 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007076 }
7077
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007078 if (!mgmt_connected)
7079 return;
7080
Andre Guedes57eb7762013-10-30 19:01:41 -03007081 if (link_type != ACL_LINK && link_type != LE_LINK)
7082 return;
7083
Johan Hedberg744cf192011-11-08 20:40:14 +02007084 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007085
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007086 bacpy(&ev.addr.bdaddr, bdaddr);
7087 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7088 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007089
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007090 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007091
7092 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007093 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007094
Johan Hedberg124f6e32012-02-09 13:50:12 +02007095 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007096 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007097}
7098
Marcel Holtmann78929242013-10-06 23:55:47 -07007099void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7100 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007101{
Andre Guedes3655bba2013-10-30 19:01:40 -03007102 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7103 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007104 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007105
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007106 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7107 hdev);
7108
Johan Hedberg333ae952015-03-17 13:48:47 +02007109 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007110 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007111 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007112
Andre Guedes3655bba2013-10-30 19:01:40 -03007113 cp = cmd->param;
7114
7115 if (bacmp(bdaddr, &cp->addr.bdaddr))
7116 return;
7117
7118 if (cp->addr.type != bdaddr_type)
7119 return;
7120
Johan Hedbergf5818c22014-12-05 13:36:02 +02007121 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007122 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007123}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007124
Marcel Holtmann445608d2013-10-06 23:55:48 -07007125void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7126 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007127{
7128 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007129
Johan Hedberg84c61d92014-08-01 11:13:30 +03007130 /* The connection is still in hci_conn_hash so test for 1
7131 * instead of 0 to know if this is the last one.
7132 */
7133 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7134 cancel_delayed_work(&hdev->power_off);
7135 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007136 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007137
Johan Hedberg4c659c32011-11-07 23:13:39 +02007138 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007139 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007140 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007141
Marcel Holtmann445608d2013-10-06 23:55:48 -07007142 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007143}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007144
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007145void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007146{
7147 struct mgmt_ev_pin_code_request ev;
7148
Johan Hedbergd8457692012-02-17 14:24:57 +02007149 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007150 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007151 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007152
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007153 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007154}
7155
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007156void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7157 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007158{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007159 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007160
Johan Hedberg333ae952015-03-17 13:48:47 +02007161 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007162 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007163 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007164
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007165 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007166 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007167}
7168
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007169void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7170 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007171{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007172 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007173
Johan Hedberg333ae952015-03-17 13:48:47 +02007174 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007175 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007176 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007177
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007178 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007179 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007180}
Johan Hedberga5c29682011-02-19 12:05:57 -03007181
Johan Hedberg744cf192011-11-08 20:40:14 +02007182int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007183 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007184 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007185{
7186 struct mgmt_ev_user_confirm_request ev;
7187
Johan Hedberg744cf192011-11-08 20:40:14 +02007188 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007189
Johan Hedberg272d90d2012-02-09 15:26:12 +02007190 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007191 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007192 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007193 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007194
Johan Hedberg744cf192011-11-08 20:40:14 +02007195 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007196 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007197}
7198
Johan Hedberg272d90d2012-02-09 15:26:12 +02007199int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007200 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007201{
7202 struct mgmt_ev_user_passkey_request ev;
7203
7204 BT_DBG("%s", hdev->name);
7205
Johan Hedberg272d90d2012-02-09 15:26:12 +02007206 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007207 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007208
7209 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007210 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007211}
7212
Brian Gix0df4c182011-11-16 13:53:13 -08007213static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007214 u8 link_type, u8 addr_type, u8 status,
7215 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007216{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007217 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007218
Johan Hedberg333ae952015-03-17 13:48:47 +02007219 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007220 if (!cmd)
7221 return -ENOENT;
7222
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007223 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007224 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007225
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007226 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007227}
7228
Johan Hedberg744cf192011-11-08 20:40:14 +02007229int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007230 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007231{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007232 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007233 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007234}
7235
Johan Hedberg272d90d2012-02-09 15:26:12 +02007236int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007237 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007238{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007239 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007240 status,
7241 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007242}
Johan Hedberg2a611692011-02-19 12:06:00 -03007243
Brian Gix604086b2011-11-23 08:28:33 -08007244int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007245 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007246{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007247 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007248 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007249}
7250
Johan Hedberg272d90d2012-02-09 15:26:12 +02007251int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007252 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007253{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007254 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007255 status,
7256 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007257}
7258
Johan Hedberg92a25252012-09-06 18:39:26 +03007259int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7260 u8 link_type, u8 addr_type, u32 passkey,
7261 u8 entered)
7262{
7263 struct mgmt_ev_passkey_notify ev;
7264
7265 BT_DBG("%s", hdev->name);
7266
7267 bacpy(&ev.addr.bdaddr, bdaddr);
7268 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7269 ev.passkey = __cpu_to_le32(passkey);
7270 ev.entered = entered;
7271
7272 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7273}
7274
Johan Hedberge1e930f2014-09-08 17:09:49 -07007275void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007276{
7277 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007278 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007279 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007280
Johan Hedberge1e930f2014-09-08 17:09:49 -07007281 bacpy(&ev.addr.bdaddr, &conn->dst);
7282 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7283 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007284
Johan Hedberge1e930f2014-09-08 17:09:49 -07007285 cmd = find_pairing(conn);
7286
7287 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7288 cmd ? cmd->sk : NULL);
7289
Johan Hedberga511b352014-12-11 21:45:45 +02007290 if (cmd) {
7291 cmd->cmd_complete(cmd, status);
7292 mgmt_pending_remove(cmd);
7293 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007294}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007295
Marcel Holtmann464996a2013-10-15 14:26:24 -07007296void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007297{
7298 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007299 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007300
7301 if (status) {
7302 u8 mgmt_err = mgmt_status(status);
7303 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007304 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007305 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007306 }
7307
Marcel Holtmann464996a2013-10-15 14:26:24 -07007308 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007309 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007310 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007311 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007312
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007313 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007314 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007315
Johan Hedberg47990ea2012-02-22 11:58:37 +02007316 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007317 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007318
7319 if (match.sk)
7320 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007321}
7322
Johan Hedberg890ea892013-03-15 17:06:52 -05007323static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007324{
Johan Hedberg890ea892013-03-15 17:06:52 -05007325 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007326 struct hci_cp_write_eir cp;
7327
Johan Hedberg976eb202012-10-24 21:12:01 +03007328 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007329 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007330
Johan Hedbergc80da272012-02-22 15:38:48 +02007331 memset(hdev->eir, 0, sizeof(hdev->eir));
7332
Johan Hedbergcacaf522012-02-21 00:52:42 +02007333 memset(&cp, 0, sizeof(cp));
7334
Johan Hedberg890ea892013-03-15 17:06:52 -05007335 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007336}
7337
Marcel Holtmann3e248562013-10-15 14:26:25 -07007338void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007339{
7340 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007341 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007342 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007343
7344 if (status) {
7345 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007346
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007347 if (enable && hci_dev_test_and_clear_flag(hdev,
7348 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007349 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007350 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007351 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007352
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007353 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7354 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007355 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007356 }
7357
7358 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007359 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007360 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007361 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007362 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007363 changed = hci_dev_test_and_clear_flag(hdev,
7364 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007365 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007366 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007367 }
7368
7369 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7370
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007371 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007372 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007373
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007374 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007375 sock_put(match.sk);
7376
Johan Hedberg890ea892013-03-15 17:06:52 -05007377 hci_req_init(&req, hdev);
7378
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007379 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7380 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007381 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7382 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007383 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007384 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007385 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007386 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007387
7388 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007389}
7390
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007391static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007392{
7393 struct cmd_lookup *match = data;
7394
Johan Hedberg90e70452012-02-23 23:09:40 +02007395 if (match->sk == NULL) {
7396 match->sk = cmd->sk;
7397 sock_hold(match->sk);
7398 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007399}
7400
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007401void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7402 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007403{
Johan Hedberg90e70452012-02-23 23:09:40 +02007404 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007405
Johan Hedberg92da6092013-03-15 17:06:55 -05007406 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7407 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7408 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007409
7410 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007411 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7412 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007413
7414 if (match.sk)
7415 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007416}
7417
Marcel Holtmann7667da32013-10-15 14:26:27 -07007418void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007419{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007420 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007421 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007422
Johan Hedberg13928972013-03-15 17:07:00 -05007423 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007424 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007425
7426 memset(&ev, 0, sizeof(ev));
7427 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007428 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007429
Johan Hedberg333ae952015-03-17 13:48:47 +02007430 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007431 if (!cmd) {
7432 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007433
Johan Hedberg13928972013-03-15 17:07:00 -05007434 /* If this is a HCI command related to powering on the
7435 * HCI dev don't send any mgmt signals.
7436 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007437 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007438 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007439 }
7440
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007441 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7442 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007443}
Szymon Jancc35938b2011-03-22 13:12:21 +01007444
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007445static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7446{
7447 int i;
7448
7449 for (i = 0; i < uuid_count; i++) {
7450 if (!memcmp(uuid, uuids[i], 16))
7451 return true;
7452 }
7453
7454 return false;
7455}
7456
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007457static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7458{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007459 u16 parsed = 0;
7460
7461 while (parsed < eir_len) {
7462 u8 field_len = eir[0];
7463 u8 uuid[16];
7464 int i;
7465
7466 if (field_len == 0)
7467 break;
7468
7469 if (eir_len - parsed < field_len + 1)
7470 break;
7471
7472 switch (eir[1]) {
7473 case EIR_UUID16_ALL:
7474 case EIR_UUID16_SOME:
7475 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007476 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007477 uuid[13] = eir[i + 3];
7478 uuid[12] = eir[i + 2];
7479 if (has_uuid(uuid, uuid_count, uuids))
7480 return true;
7481 }
7482 break;
7483 case EIR_UUID32_ALL:
7484 case EIR_UUID32_SOME:
7485 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007486 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007487 uuid[15] = eir[i + 5];
7488 uuid[14] = eir[i + 4];
7489 uuid[13] = eir[i + 3];
7490 uuid[12] = eir[i + 2];
7491 if (has_uuid(uuid, uuid_count, uuids))
7492 return true;
7493 }
7494 break;
7495 case EIR_UUID128_ALL:
7496 case EIR_UUID128_SOME:
7497 for (i = 0; i + 17 <= field_len; i += 16) {
7498 memcpy(uuid, eir + i + 2, 16);
7499 if (has_uuid(uuid, uuid_count, uuids))
7500 return true;
7501 }
7502 break;
7503 }
7504
7505 parsed += field_len + 1;
7506 eir += field_len + 1;
7507 }
7508
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007509 return false;
7510}
7511
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007512static void restart_le_scan(struct hci_dev *hdev)
7513{
7514 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007515 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007516 return;
7517
7518 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7519 hdev->discovery.scan_start +
7520 hdev->discovery.scan_duration))
7521 return;
7522
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007523 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007524 DISCOV_LE_RESTART_DELAY);
7525}
7526
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007527static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7528 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7529{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007530 /* If a RSSI threshold has been specified, and
7531 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7532 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7533 * is set, let it through for further processing, as we might need to
7534 * restart the scan.
7535 *
7536 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7537 * the results are also dropped.
7538 */
7539 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7540 (rssi == HCI_RSSI_INVALID ||
7541 (rssi < hdev->discovery.rssi &&
7542 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7543 return false;
7544
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007545 if (hdev->discovery.uuid_count != 0) {
7546 /* If a list of UUIDs is provided in filter, results with no
7547 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007548 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007549 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7550 hdev->discovery.uuids) &&
7551 !eir_has_uuids(scan_rsp, scan_rsp_len,
7552 hdev->discovery.uuid_count,
7553 hdev->discovery.uuids))
7554 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007555 }
7556
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007557 /* If duplicate filtering does not report RSSI changes, then restart
7558 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007559 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007560 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7561 restart_le_scan(hdev);
7562
7563 /* Validate RSSI value against the RSSI threshold once more. */
7564 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7565 rssi < hdev->discovery.rssi)
7566 return false;
7567 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007568
7569 return true;
7570}
7571
Marcel Holtmann901801b2013-10-06 23:55:51 -07007572void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007573 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7574 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007575{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007576 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007577 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007578 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007579
Johan Hedberg75ce2082014-07-02 22:42:01 +03007580 /* Don't send events for a non-kernel initiated discovery. With
7581 * LE one exception is if we have pend_le_reports > 0 in which
7582 * case we're doing passive scanning and want these events.
7583 */
7584 if (!hci_discovery_active(hdev)) {
7585 if (link_type == ACL_LINK)
7586 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007587 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007588 return;
7589 }
Andre Guedes12602d02013-04-30 15:29:40 -03007590
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007591 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007592 /* We are using service discovery */
7593 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7594 scan_rsp_len))
7595 return;
7596 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007597
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007598 /* Make sure that the buffer is big enough. The 5 extra bytes
7599 * are for the potential CoD field.
7600 */
7601 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007602 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007603
Johan Hedberg1dc06092012-01-15 21:01:23 +02007604 memset(buf, 0, sizeof(buf));
7605
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007606 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7607 * RSSI value was reported as 0 when not available. This behavior
7608 * is kept when using device discovery. This is required for full
7609 * backwards compatibility with the API.
7610 *
7611 * However when using service discovery, the value 127 will be
7612 * returned when the RSSI is not available.
7613 */
Szymon Janc91200e92015-01-22 16:57:05 +01007614 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7615 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007616 rssi = 0;
7617
Johan Hedberg841c5642014-07-07 12:45:54 +03007618 bacpy(&ev->addr.bdaddr, bdaddr);
7619 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007620 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007621 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007622
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007623 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007624 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007625 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007626
Johan Hedberg1dc06092012-01-15 21:01:23 +02007627 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7628 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007629 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007630
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007631 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007632 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007633 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007634
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007635 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7636 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007637
Marcel Holtmann901801b2013-10-06 23:55:51 -07007638 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007639}
Johan Hedberga88a9652011-03-30 13:18:12 +03007640
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007641void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7642 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007643{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007644 struct mgmt_ev_device_found *ev;
7645 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7646 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007647
Johan Hedbergb644ba32012-01-17 21:48:47 +02007648 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007649
Johan Hedbergb644ba32012-01-17 21:48:47 +02007650 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007651
Johan Hedbergb644ba32012-01-17 21:48:47 +02007652 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007653 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007654 ev->rssi = rssi;
7655
7656 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007657 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007658
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007659 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007660
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007661 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007662}
Johan Hedberg314b2382011-04-27 10:29:57 -04007663
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007664void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007665{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007666 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007667
Andre Guedes343fb142011-11-22 17:14:19 -03007668 BT_DBG("%s discovering %u", hdev->name, discovering);
7669
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007670 memset(&ev, 0, sizeof(ev));
7671 ev.type = hdev->discovery.type;
7672 ev.discovering = discovering;
7673
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007674 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007675}
Antti Julku5e762442011-08-25 16:48:02 +03007676
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007677static struct hci_mgmt_chan chan = {
7678 .channel = HCI_CHANNEL_CONTROL,
7679 .handler_count = ARRAY_SIZE(mgmt_handlers),
7680 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007681 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007682};
7683
7684int mgmt_init(void)
7685{
7686 return hci_mgmt_chan_register(&chan);
7687}
7688
7689void mgmt_exit(void)
7690{
7691 hci_mgmt_chan_unregister(&chan);
7692}