blob: 89954bb19222ee4adcde69ae1149f030a6f0f249 [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 Hedberg87510972016-07-13 10:57:18 +030041#define MGMT_REVISION 13
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 Hedberg78b781c2016-01-05 13:19:32 +0200106 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200107 MGMT_OP_READ_EXT_INFO,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200108};
109
110static const u16 mgmt_events[] = {
111 MGMT_EV_CONTROLLER_ERROR,
112 MGMT_EV_INDEX_ADDED,
113 MGMT_EV_INDEX_REMOVED,
114 MGMT_EV_NEW_SETTINGS,
115 MGMT_EV_CLASS_OF_DEV_CHANGED,
116 MGMT_EV_LOCAL_NAME_CHANGED,
117 MGMT_EV_NEW_LINK_KEY,
118 MGMT_EV_NEW_LONG_TERM_KEY,
119 MGMT_EV_DEVICE_CONNECTED,
120 MGMT_EV_DEVICE_DISCONNECTED,
121 MGMT_EV_CONNECT_FAILED,
122 MGMT_EV_PIN_CODE_REQUEST,
123 MGMT_EV_USER_CONFIRM_REQUEST,
124 MGMT_EV_USER_PASSKEY_REQUEST,
125 MGMT_EV_AUTH_FAILED,
126 MGMT_EV_DEVICE_FOUND,
127 MGMT_EV_DISCOVERING,
128 MGMT_EV_DEVICE_BLOCKED,
129 MGMT_EV_DEVICE_UNBLOCKED,
130 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300131 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800132 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700133 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200134 MGMT_EV_DEVICE_ADDED,
135 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300136 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200137 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200138 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200139 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700140 MGMT_EV_EXT_INDEX_ADDED,
141 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700142 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700143 MGMT_EV_ADVERTISING_ADDED,
144 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200145 MGMT_EV_EXT_INFO_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200146};
147
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700148static const u16 mgmt_untrusted_commands[] = {
149 MGMT_OP_READ_INDEX_LIST,
150 MGMT_OP_READ_INFO,
151 MGMT_OP_READ_UNCONF_INDEX_LIST,
152 MGMT_OP_READ_CONFIG_INFO,
153 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200154 MGMT_OP_READ_EXT_INFO,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700155};
156
157static const u16 mgmt_untrusted_events[] = {
158 MGMT_EV_INDEX_ADDED,
159 MGMT_EV_INDEX_REMOVED,
160 MGMT_EV_NEW_SETTINGS,
161 MGMT_EV_CLASS_OF_DEV_CHANGED,
162 MGMT_EV_LOCAL_NAME_CHANGED,
163 MGMT_EV_UNCONF_INDEX_ADDED,
164 MGMT_EV_UNCONF_INDEX_REMOVED,
165 MGMT_EV_NEW_CONFIG_OPTIONS,
166 MGMT_EV_EXT_INDEX_ADDED,
167 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200168 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700169};
170
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800171#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200172
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200173#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
174 "\x00\x00\x00\x00\x00\x00\x00\x00"
175
Johan Hedbergca69b792011-11-11 18:10:00 +0200176/* HCI to MGMT error code conversion table */
177static u8 mgmt_status_table[] = {
178 MGMT_STATUS_SUCCESS,
179 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
180 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
181 MGMT_STATUS_FAILED, /* Hardware Failure */
182 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200184 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200185 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
186 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
187 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
188 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
189 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
190 MGMT_STATUS_BUSY, /* Command Disallowed */
191 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
192 MGMT_STATUS_REJECTED, /* Rejected Security */
193 MGMT_STATUS_REJECTED, /* Rejected Personal */
194 MGMT_STATUS_TIMEOUT, /* Host Timeout */
195 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
196 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
197 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
198 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
199 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
200 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
201 MGMT_STATUS_BUSY, /* Repeated Attempts */
202 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
203 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
204 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
205 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
206 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
207 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
208 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
209 MGMT_STATUS_FAILED, /* Unspecified Error */
210 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
211 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
212 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
213 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
214 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
215 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
216 MGMT_STATUS_FAILED, /* Unit Link Key Used */
217 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
218 MGMT_STATUS_TIMEOUT, /* Instant Passed */
219 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
220 MGMT_STATUS_FAILED, /* Transaction Collision */
221 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
222 MGMT_STATUS_REJECTED, /* QoS Rejected */
223 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
224 MGMT_STATUS_REJECTED, /* Insufficient Security */
225 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
226 MGMT_STATUS_BUSY, /* Role Switch Pending */
227 MGMT_STATUS_FAILED, /* Slot Violation */
228 MGMT_STATUS_FAILED, /* Role Switch Failed */
229 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
230 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
231 MGMT_STATUS_BUSY, /* Host Busy Pairing */
232 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
233 MGMT_STATUS_BUSY, /* Controller Busy */
234 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
235 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
236 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
237 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
238 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
239};
240
241static u8 mgmt_status(u8 hci_status)
242{
243 if (hci_status < ARRAY_SIZE(mgmt_status_table))
244 return mgmt_status_table[hci_status];
245
246 return MGMT_STATUS_FAILED;
247}
248
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700249static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
250 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700251{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700252 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
253 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700254}
255
Marcel Holtmann72000df2015-03-16 16:11:21 -0700256static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
257 u16 len, int flag, struct sock *skip_sk)
258{
259 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
260 flag, skip_sk);
261}
262
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200263static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
264 struct sock *skip_sk)
265{
266 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700267 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200268}
269
Johan Hedberg85813a72015-10-21 18:02:59 +0300270static u8 le_addr_type(u8 mgmt_addr_type)
271{
272 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
273 return ADDR_LE_DEV_PUBLIC;
274 else
275 return ADDR_LE_DEV_RANDOM;
276}
277
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200278void mgmt_fill_version_info(void *ver)
279{
280 struct mgmt_rp_read_version *rp = ver;
281
282 rp->version = MGMT_VERSION;
283 rp->revision = cpu_to_le16(MGMT_REVISION);
284}
285
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300286static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
287 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200288{
289 struct mgmt_rp_read_version rp;
290
291 BT_DBG("sock %p", sk);
292
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200293 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200294
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200295 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
296 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200297}
298
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300299static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
300 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200301{
302 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700303 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 size_t rp_size;
305 int i, err;
306
307 BT_DBG("sock %p", sk);
308
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700309 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
310 num_commands = ARRAY_SIZE(mgmt_commands);
311 num_events = ARRAY_SIZE(mgmt_events);
312 } else {
313 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
314 num_events = ARRAY_SIZE(mgmt_untrusted_events);
315 }
316
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200317 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
318
319 rp = kmalloc(rp_size, GFP_KERNEL);
320 if (!rp)
321 return -ENOMEM;
322
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700323 rp->num_commands = cpu_to_le16(num_commands);
324 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200325
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700326 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
327 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200328
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700329 for (i = 0; i < num_commands; i++, opcode++)
330 put_unaligned_le16(mgmt_commands[i], opcode);
331
332 for (i = 0; i < num_events; i++, opcode++)
333 put_unaligned_le16(mgmt_events[i], opcode);
334 } else {
335 __le16 *opcode = rp->opcodes;
336
337 for (i = 0; i < num_commands; i++, opcode++)
338 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
339
340 for (i = 0; i < num_events; i++, opcode++)
341 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
342 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200343
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200344 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
345 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200346 kfree(rp);
347
348 return err;
349}
350
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300351static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
352 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200355 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200356 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300358 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
360 BT_DBG("sock %p", sk);
361
362 read_lock(&hci_dev_list_lock);
363
364 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300365 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200366 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700367 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700368 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200369 }
370
Johan Hedberga38528f2011-01-22 06:46:43 +0200371 rp_len = sizeof(*rp) + (2 * count);
372 rp = kmalloc(rp_len, GFP_ATOMIC);
373 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100374 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200375 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100376 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200377
Johan Hedberg476e44c2012-10-19 20:10:46 +0300378 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200379 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700380 if (hci_dev_test_flag(d, HCI_SETUP) ||
381 hci_dev_test_flag(d, HCI_CONFIG) ||
382 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383 continue;
384
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200385 /* Devices marked as raw-only are neither configured
386 * nor unconfigured controllers.
387 */
388 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700389 continue;
390
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200391 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700392 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700393 rp->index[count++] = cpu_to_le16(d->id);
394 BT_DBG("Added hci%u", d->id);
395 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 }
397
Johan Hedberg476e44c2012-10-19 20:10:46 +0300398 rp->num_controllers = cpu_to_le16(count);
399 rp_len = sizeof(*rp) + (2 * count);
400
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200401 read_unlock(&hci_dev_list_lock);
402
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200403 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
404 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200405
Johan Hedberga38528f2011-01-22 06:46:43 +0200406 kfree(rp);
407
408 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200409}
410
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200411static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
412 void *data, u16 data_len)
413{
414 struct mgmt_rp_read_unconf_index_list *rp;
415 struct hci_dev *d;
416 size_t rp_len;
417 u16 count;
418 int err;
419
420 BT_DBG("sock %p", sk);
421
422 read_lock(&hci_dev_list_lock);
423
424 count = 0;
425 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200426 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700427 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200428 count++;
429 }
430
431 rp_len = sizeof(*rp) + (2 * count);
432 rp = kmalloc(rp_len, GFP_ATOMIC);
433 if (!rp) {
434 read_unlock(&hci_dev_list_lock);
435 return -ENOMEM;
436 }
437
438 count = 0;
439 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700440 if (hci_dev_test_flag(d, HCI_SETUP) ||
441 hci_dev_test_flag(d, HCI_CONFIG) ||
442 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200443 continue;
444
445 /* Devices marked as raw-only are neither configured
446 * nor unconfigured controllers.
447 */
448 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
449 continue;
450
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200451 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700452 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200453 rp->index[count++] = cpu_to_le16(d->id);
454 BT_DBG("Added hci%u", d->id);
455 }
456 }
457
458 rp->num_controllers = cpu_to_le16(count);
459 rp_len = sizeof(*rp) + (2 * count);
460
461 read_unlock(&hci_dev_list_lock);
462
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200463 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
464 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200465
466 kfree(rp);
467
468 return err;
469}
470
Marcel Holtmann96f14742015-03-14 19:27:57 -0700471static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
472 void *data, u16 data_len)
473{
474 struct mgmt_rp_read_ext_index_list *rp;
475 struct hci_dev *d;
476 size_t rp_len;
477 u16 count;
478 int err;
479
480 BT_DBG("sock %p", sk);
481
482 read_lock(&hci_dev_list_lock);
483
484 count = 0;
485 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200486 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700487 count++;
488 }
489
490 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
491 rp = kmalloc(rp_len, GFP_ATOMIC);
492 if (!rp) {
493 read_unlock(&hci_dev_list_lock);
494 return -ENOMEM;
495 }
496
497 count = 0;
498 list_for_each_entry(d, &hci_dev_list, list) {
499 if (hci_dev_test_flag(d, HCI_SETUP) ||
500 hci_dev_test_flag(d, HCI_CONFIG) ||
501 hci_dev_test_flag(d, HCI_USER_CHANNEL))
502 continue;
503
504 /* Devices marked as raw-only are neither configured
505 * nor unconfigured controllers.
506 */
507 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
508 continue;
509
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200510 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700511 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
512 rp->entry[count].type = 0x01;
513 else
514 rp->entry[count].type = 0x00;
515 } else if (d->dev_type == HCI_AMP) {
516 rp->entry[count].type = 0x02;
517 } else {
518 continue;
519 }
520
521 rp->entry[count].bus = d->bus;
522 rp->entry[count++].index = cpu_to_le16(d->id);
523 BT_DBG("Added hci%u", d->id);
524 }
525
526 rp->num_controllers = cpu_to_le16(count);
527 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
528
529 read_unlock(&hci_dev_list_lock);
530
531 /* If this command is called at least once, then all the
532 * default index and unconfigured index events are disabled
533 * and from now on only extended index events are used.
534 */
535 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
536 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
537 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
538
539 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
540 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
541
542 kfree(rp);
543
544 return err;
545}
546
Marcel Holtmanndbece372014-07-04 18:11:55 +0200547static bool is_configured(struct hci_dev *hdev)
548{
549 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700550 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200551 return false;
552
553 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
554 !bacmp(&hdev->public_addr, BDADDR_ANY))
555 return false;
556
557 return true;
558}
559
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200560static __le32 get_missing_options(struct hci_dev *hdev)
561{
562 u32 options = 0;
563
Marcel Holtmanndbece372014-07-04 18:11:55 +0200564 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700565 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200566 options |= MGMT_OPTION_EXTERNAL_CONFIG;
567
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200568 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
569 !bacmp(&hdev->public_addr, BDADDR_ANY))
570 options |= MGMT_OPTION_PUBLIC_ADDRESS;
571
572 return cpu_to_le32(options);
573}
574
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200575static int new_options(struct hci_dev *hdev, struct sock *skip)
576{
577 __le32 options = get_missing_options(hdev);
578
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200579 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
580 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200581}
582
Marcel Holtmanndbece372014-07-04 18:11:55 +0200583static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
584{
585 __le32 options = get_missing_options(hdev);
586
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200587 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
588 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200589}
590
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591static int read_config_info(struct sock *sk, struct hci_dev *hdev,
592 void *data, u16 data_len)
593{
594 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200595 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200596
597 BT_DBG("sock %p %s", sk, hdev->name);
598
599 hci_dev_lock(hdev);
600
601 memset(&rp, 0, sizeof(rp));
602 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200604 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
605 options |= MGMT_OPTION_EXTERNAL_CONFIG;
606
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200608 options |= MGMT_OPTION_PUBLIC_ADDRESS;
609
610 rp.supported_options = cpu_to_le32(options);
611 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612
613 hci_dev_unlock(hdev);
614
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200615 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
616 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200617}
618
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200619static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200620{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200621 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200622
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200623 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300624 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800625 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300626 settings |= MGMT_SETTING_CONNECTABLE;
627 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200628
Andre Guedesed3fa312012-07-24 15:03:46 -0300629 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500630 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
631 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200632 settings |= MGMT_SETTING_BREDR;
633 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700634
635 if (lmp_ssp_capable(hdev)) {
636 settings |= MGMT_SETTING_SSP;
637 settings |= MGMT_SETTING_HS;
638 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800639
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800640 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800641 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700642 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100643
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300644 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200645 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300646 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300647 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200648 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800649 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300650 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200651
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200652 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
653 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200654 settings |= MGMT_SETTING_CONFIGURATION;
655
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200656 return settings;
657}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200658
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200659static u32 get_current_settings(struct hci_dev *hdev)
660{
661 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200662
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200663 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100664 settings |= MGMT_SETTING_POWERED;
665
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700666 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200667 settings |= MGMT_SETTING_CONNECTABLE;
668
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700669 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500670 settings |= MGMT_SETTING_FAST_CONNECTABLE;
671
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700672 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200673 settings |= MGMT_SETTING_DISCOVERABLE;
674
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700675 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300676 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700678 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200679 settings |= MGMT_SETTING_BREDR;
680
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700681 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200682 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200683
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700684 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200685 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200686
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700687 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200688 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200689
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700690 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200691 settings |= MGMT_SETTING_HS;
692
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700693 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300694 settings |= MGMT_SETTING_ADVERTISING;
695
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700696 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800697 settings |= MGMT_SETTING_SECURE_CONN;
698
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700699 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800700 settings |= MGMT_SETTING_DEBUG_KEYS;
701
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700702 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200703 settings |= MGMT_SETTING_PRIVACY;
704
Marcel Holtmann93690c22015-03-06 10:11:21 -0800705 /* The current setting for static address has two purposes. The
706 * first is to indicate if the static address will be used and
707 * the second is to indicate if it is actually set.
708 *
709 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700710 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800711 * address is actually used decides if the flag is set or not.
712 *
713 * For single mode LE only controllers and dual-mode controllers
714 * with BR/EDR disabled, the existence of the static address will
715 * be evaluated.
716 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700717 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700718 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800719 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
720 if (bacmp(&hdev->static_addr, BDADDR_ANY))
721 settings |= MGMT_SETTING_STATIC_ADDRESS;
722 }
723
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200724 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200725}
726
Johan Hedberg333ae952015-03-17 13:48:47 +0200727static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
728{
729 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
730}
731
Johan Hedberg333ae952015-03-17 13:48:47 +0200732static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
733 struct hci_dev *hdev,
734 const void *data)
735{
736 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
737}
738
Johan Hedbergf2252572015-11-18 12:49:20 +0200739u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300740{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200741 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300742
743 /* If there's a pending mgmt command the flags will not yet have
744 * their final values, so check for this first.
745 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200746 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300747 if (cmd) {
748 struct mgmt_mode *cp = cmd->param;
749 if (cp->val == 0x01)
750 return LE_AD_GENERAL;
751 else if (cp->val == 0x02)
752 return LE_AD_LIMITED;
753 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700754 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300755 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700756 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300757 return LE_AD_GENERAL;
758 }
759
760 return 0;
761}
762
Johan Hedbergf2252572015-11-18 12:49:20 +0200763bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700764{
765 struct mgmt_pending_cmd *cmd;
766
767 /* If there's a pending mgmt command the flag will not yet have
768 * it's final value, so check for this first.
769 */
770 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
771 if (cmd) {
772 struct mgmt_mode *cp = cmd->param;
773
774 return cp->val;
775 }
776
777 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
778}
779
Johan Hedberg7d785252011-12-15 00:47:39 +0200780static void service_cache_off(struct work_struct *work)
781{
782 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300783 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500784 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200785
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700786 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200787 return;
788
Johan Hedberg890ea892013-03-15 17:06:52 -0500789 hci_req_init(&req, hdev);
790
Johan Hedberg7d785252011-12-15 00:47:39 +0200791 hci_dev_lock(hdev);
792
Johan Hedbergb1a89172015-11-25 16:15:42 +0200793 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200794 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200795
796 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500797
798 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200799}
800
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200801static void rpa_expired(struct work_struct *work)
802{
803 struct hci_dev *hdev = container_of(work, struct hci_dev,
804 rpa_expired.work);
805 struct hci_request req;
806
807 BT_DBG("");
808
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700809 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200810
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700811 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200812 return;
813
814 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200815 * controller happens in the hci_req_enable_advertising()
816 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200817 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200818 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +0200819 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200820 hci_req_run(&req, NULL);
821}
822
Johan Hedberg6a919082012-02-28 06:17:26 +0200823static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200824{
Marcel Holtmann238be782015-03-13 02:11:06 -0700825 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200826 return;
827
Johan Hedberg4f87da82012-03-02 19:55:56 +0200828 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200829 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200830
Johan Hedberg4f87da82012-03-02 19:55:56 +0200831 /* Non-mgmt controlled devices get this bit set
832 * implicitly so that pairing works for them, however
833 * for mgmt we require user-space to explicitly enable
834 * it
835 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700836 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200837}
838
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200839static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300840 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200841{
842 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200843
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200844 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200845
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300846 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200847
Johan Hedberg03811012010-12-08 00:21:06 +0200848 memset(&rp, 0, sizeof(rp));
849
Johan Hedberg03811012010-12-08 00:21:06 +0200850 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200851
852 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200853 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200854
855 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
856 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
857
858 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200859
860 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200861 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200862
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300863 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200864
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200865 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
866 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200867}
868
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200869static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
870 u8 data_len)
871{
872 eir[eir_len++] = sizeof(type) + data_len;
873 eir[eir_len++] = type;
874 memcpy(&eir[eir_len], data, data_len);
875 eir_len += data_len;
876
877 return eir_len;
878}
879
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200880static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
881 void *data, u16 data_len)
882{
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200883 struct mgmt_rp_read_ext_info *rp;
884 char buff[512];
885 u16 eir_len = 0;
886 u8 name_len;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200887
888 BT_DBG("sock %p %s", sk, hdev->name);
889
890 hci_dev_lock(hdev);
891
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200892 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
893 eir_len = eir_append_data(buff, eir_len,
894 EIR_CLASS_OF_DEV,
895 hdev->dev_class, 3);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200896
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200897 name_len = strlen(hdev->dev_name);
898 eir_len = eir_append_data(buff, eir_len, EIR_NAME_COMPLETE,
899 hdev->dev_name, name_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200900
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200901 name_len = strlen(hdev->short_name);
902 eir_len = eir_append_data(buff, eir_len, EIR_NAME_SHORT,
903 hdev->short_name, name_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200904
Wei Yongjun3e36ca42016-09-10 12:21:22 +0000905 rp = kzalloc(sizeof(*rp) + eir_len, GFP_KERNEL);
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200906 if (!rp)
907 return -ENOMEM;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200908
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200909 rp->eir_len = cpu_to_le16(eir_len);
910 memcpy(rp->eir, buff, eir_len);
911
912 bacpy(&rp->bdaddr, &hdev->bdaddr);
913
914 rp->version = hdev->hci_ver;
915 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
916
917 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
918 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200919
920 hci_dev_unlock(hdev);
921
922 /* If this command is called at least once, then the events
923 * for class of device and local name changes are disabled
924 * and only the new extended controller information event
925 * is used.
926 */
927 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
928 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
929 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
930
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200931 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
932 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200933}
934
935static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
936{
937 struct mgmt_ev_ext_info_changed ev;
938
939 ev.eir_len = cpu_to_le16(0);
940
941 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, &ev,
942 sizeof(ev), HCI_MGMT_EXT_INFO_EVENTS, skip);
943}
944
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200945static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200946{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200947 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200948
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200949 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
950 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200951}
952
Marcel Holtmann1904a852015-01-11 13:50:44 -0800953static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200954{
955 BT_DBG("%s status 0x%02x", hdev->name, status);
956
Johan Hedberga3172b72014-02-28 09:33:44 +0200957 if (hci_conn_count(hdev) == 0) {
958 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200959 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200960 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200961}
962
Johan Hedbergf2252572015-11-18 12:49:20 +0200963void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700964{
965 struct mgmt_ev_advertising_added ev;
966
967 ev.instance = instance;
968
969 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
970}
971
Johan Hedbergf2252572015-11-18 12:49:20 +0200972void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
973 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700974{
975 struct mgmt_ev_advertising_removed ev;
976
977 ev.instance = instance;
978
979 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
980}
981
Florian Grandel7816b822015-06-18 03:16:45 +0200982static void cancel_adv_timeout(struct hci_dev *hdev)
983{
984 if (hdev->adv_instance_timeout) {
985 hdev->adv_instance_timeout = 0;
986 cancel_delayed_work(&hdev->adv_instance_expire);
987 }
988}
989
Johan Hedberg8b064a32014-02-24 14:52:22 +0200990static int clean_up_hci_state(struct hci_dev *hdev)
991{
992 struct hci_request req;
993 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300994 bool discov_stopped;
995 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200996
997 hci_req_init(&req, hdev);
998
999 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1000 test_bit(HCI_PSCAN, &hdev->flags)) {
1001 u8 scan = 0x00;
1002 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1003 }
1004
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001005 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001006
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001007 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001008 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001009
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001010 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001011
1012 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001013 /* 0x15 == Terminated due to Power Off */
1014 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001015 }
1016
Johan Hedberg23a48092014-07-08 16:05:06 +03001017 err = hci_req_run(&req, clean_up_hci_complete);
1018 if (!err && discov_stopped)
1019 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1020
1021 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001022}
1023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001024static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001025 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001026{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001027 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001028 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001029 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001031 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032
Johan Hedberga7e80f22013-01-09 16:05:19 +02001033 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001034 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1035 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001036
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001037 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038
Johan Hedberg333ae952015-03-17 13:48:47 +02001039 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001040 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1041 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001042 goto failed;
1043 }
1044
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001045 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001046 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047 goto failed;
1048 }
1049
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001050 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1051 if (!cmd) {
1052 err = -ENOMEM;
1053 goto failed;
1054 }
1055
Johan Hedberg8b064a32014-02-24 14:52:22 +02001056 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001057 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001058 err = 0;
1059 } else {
1060 /* Disconnect connections, stop scans, etc */
1061 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001062 if (!err)
1063 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1064 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001065
Johan Hedberg8b064a32014-02-24 14:52:22 +02001066 /* ENODATA means there were no HCI commands queued */
1067 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001068 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001069 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1070 err = 0;
1071 }
1072 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001073
1074failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001075 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001076 return err;
1077}
1078
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001079static int new_settings(struct hci_dev *hdev, struct sock *skip)
1080{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001081 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001082
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001083 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1084 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001085}
1086
Johan Hedberg91a668b2014-07-09 13:28:26 +03001087int mgmt_new_settings(struct hci_dev *hdev)
1088{
1089 return new_settings(hdev, NULL);
1090}
1091
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001092struct cmd_lookup {
1093 struct sock *sk;
1094 struct hci_dev *hdev;
1095 u8 mgmt_status;
1096};
1097
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001098static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001099{
1100 struct cmd_lookup *match = data;
1101
1102 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1103
1104 list_del(&cmd->list);
1105
1106 if (match->sk == NULL) {
1107 match->sk = cmd->sk;
1108 sock_hold(match->sk);
1109 }
1110
1111 mgmt_pending_free(cmd);
1112}
1113
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001114static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001115{
1116 u8 *status = data;
1117
Johan Hedberga69e8372015-03-06 21:08:53 +02001118 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001119 mgmt_pending_remove(cmd);
1120}
1121
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001122static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001123{
1124 if (cmd->cmd_complete) {
1125 u8 *status = data;
1126
1127 cmd->cmd_complete(cmd, *status);
1128 mgmt_pending_remove(cmd);
1129
1130 return;
1131 }
1132
1133 cmd_status_rsp(cmd, data);
1134}
1135
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001136static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001137{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001138 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1139 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001140}
1141
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001142static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001143{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001144 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1145 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001146}
1147
Johan Hedberge6fe7982013-10-02 15:45:22 +03001148static u8 mgmt_bredr_support(struct hci_dev *hdev)
1149{
1150 if (!lmp_bredr_capable(hdev))
1151 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001152 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001153 return MGMT_STATUS_REJECTED;
1154 else
1155 return MGMT_STATUS_SUCCESS;
1156}
1157
1158static u8 mgmt_le_support(struct hci_dev *hdev)
1159{
1160 if (!lmp_le_capable(hdev))
1161 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001162 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001163 return MGMT_STATUS_REJECTED;
1164 else
1165 return MGMT_STATUS_SUCCESS;
1166}
1167
Johan Hedbergaed1a882015-11-22 17:24:44 +03001168void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001169{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001170 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001171
1172 BT_DBG("status 0x%02x", status);
1173
1174 hci_dev_lock(hdev);
1175
Johan Hedberg333ae952015-03-17 13:48:47 +02001176 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001177 if (!cmd)
1178 goto unlock;
1179
1180 if (status) {
1181 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001182 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001183 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001184 goto remove_cmd;
1185 }
1186
Johan Hedbergaed1a882015-11-22 17:24:44 +03001187 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1188 hdev->discov_timeout > 0) {
1189 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1190 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001191 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001192
1193 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001194 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001195
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001196remove_cmd:
1197 mgmt_pending_remove(cmd);
1198
1199unlock:
1200 hci_dev_unlock(hdev);
1201}
1202
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001203static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001204 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001205{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001206 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001207 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001208 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001209 int err;
1210
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001211 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001212
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001213 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1214 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001215 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1216 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001217
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001218 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001219 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1220 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001221
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001222 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001223
1224 /* Disabling discoverable requires that no timeout is set,
1225 * and enabling limited discoverable requires a timeout.
1226 */
1227 if ((cp->val == 0x00 && timeout > 0) ||
1228 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001229 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1230 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001231
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001232 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001233
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001234 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001235 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1236 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001237 goto failed;
1238 }
1239
Johan Hedberg333ae952015-03-17 13:48:47 +02001240 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1241 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001242 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1243 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001244 goto failed;
1245 }
1246
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001247 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001248 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1249 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001250 goto failed;
1251 }
1252
1253 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001254 bool changed = false;
1255
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001256 /* Setting limited discoverable when powered off is
1257 * not a valid operation since it requires a timeout
1258 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1259 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001260 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001261 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001262 changed = true;
1263 }
1264
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001265 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001266 if (err < 0)
1267 goto failed;
1268
1269 if (changed)
1270 err = new_settings(hdev, sk);
1271
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001272 goto failed;
1273 }
1274
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001275 /* If the current mode is the same, then just update the timeout
1276 * value with the new value. And if only the timeout gets updated,
1277 * then no need for any HCI transactions.
1278 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001279 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1280 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1281 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001282 cancel_delayed_work(&hdev->discov_off);
1283 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001284
Marcel Holtmann36261542013-10-15 08:28:51 -07001285 if (cp->val && hdev->discov_timeout > 0) {
1286 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001287 queue_delayed_work(hdev->req_workqueue,
1288 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001289 }
1290
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001291 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001292 goto failed;
1293 }
1294
1295 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1296 if (!cmd) {
1297 err = -ENOMEM;
1298 goto failed;
1299 }
1300
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001301 /* Cancel any potential discoverable timeout that might be
1302 * still active and store new timeout value. The arming of
1303 * the timeout happens in the complete handler.
1304 */
1305 cancel_delayed_work(&hdev->discov_off);
1306 hdev->discov_timeout = timeout;
1307
Johan Hedbergaed1a882015-11-22 17:24:44 +03001308 if (cp->val)
1309 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1310 else
1311 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1312
Johan Hedbergb456f872013-10-19 23:38:22 +03001313 /* Limited discoverable mode */
1314 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001315 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001316 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001317 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001318
Johan Hedbergaed1a882015-11-22 17:24:44 +03001319 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1320 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001321
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001322failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001323 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001324 return err;
1325}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001326
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001327void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001328{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001329 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001330
1331 BT_DBG("status 0x%02x", status);
1332
1333 hci_dev_lock(hdev);
1334
Johan Hedberg333ae952015-03-17 13:48:47 +02001335 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001336 if (!cmd)
1337 goto unlock;
1338
Johan Hedberg37438c12013-10-14 16:20:05 +03001339 if (status) {
1340 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001341 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001342 goto remove_cmd;
1343 }
1344
Johan Hedberg2b76f452013-03-15 17:07:04 -05001345 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001346 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001347
Johan Hedberg37438c12013-10-14 16:20:05 +03001348remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001349 mgmt_pending_remove(cmd);
1350
1351unlock:
1352 hci_dev_unlock(hdev);
1353}
1354
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001355static int set_connectable_update_settings(struct hci_dev *hdev,
1356 struct sock *sk, u8 val)
1357{
1358 bool changed = false;
1359 int err;
1360
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001361 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001362 changed = true;
1363
1364 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001365 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001366 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001367 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1368 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001369 }
1370
1371 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1372 if (err < 0)
1373 return err;
1374
Johan Hedberg562064e2014-07-08 16:35:34 +03001375 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001376 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001377 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001378 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001379 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001380
1381 return 0;
1382}
1383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001384static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001385 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001386{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001387 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001388 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001389 int err;
1390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001391 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001392
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001393 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1394 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001395 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1396 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001397
Johan Hedberga7e80f22013-01-09 16:05:19 +02001398 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001399 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1400 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001401
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001402 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001403
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001404 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001405 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001406 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001407 }
1408
Johan Hedberg333ae952015-03-17 13:48:47 +02001409 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1410 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001411 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1412 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001413 goto failed;
1414 }
1415
Johan Hedberg73f22f62010-12-29 16:00:25 +02001416 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1417 if (!cmd) {
1418 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001419 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001420 }
1421
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001422 if (cp->val) {
1423 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1424 } else {
1425 if (hdev->discov_timeout > 0)
1426 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001427
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001428 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1429 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1430 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001431 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001432
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001433 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1434 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001435
1436failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001437 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001438 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001439}
1440
Johan Hedbergb2939472014-07-30 09:22:23 +03001441static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001442 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001443{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001444 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001445 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001446 int err;
1447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001448 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001449
Johan Hedberga7e80f22013-01-09 16:05:19 +02001450 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001451 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1452 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001453
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001454 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001455
1456 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001457 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001458 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001459 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001460
Johan Hedbergb2939472014-07-30 09:22:23 +03001461 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001462 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001463 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001464
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001465 if (changed) {
1466 /* In limited privacy mode the change of bondable mode
1467 * may affect the local advertising address.
1468 */
1469 if (hdev_is_powered(hdev) &&
1470 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1471 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1472 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1473 queue_work(hdev->req_workqueue,
1474 &hdev->discoverable_update);
1475
Marcel Holtmann55594352013-10-06 16:11:57 -07001476 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001477 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001478
Marcel Holtmann55594352013-10-06 16:11:57 -07001479unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001480 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001481 return err;
1482}
1483
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001484static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1485 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001486{
1487 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001488 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001489 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001490 int err;
1491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001492 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001493
Johan Hedberge6fe7982013-10-02 15:45:22 +03001494 status = mgmt_bredr_support(hdev);
1495 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001496 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1497 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001498
Johan Hedberga7e80f22013-01-09 16:05:19 +02001499 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001500 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1501 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001502
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001503 hci_dev_lock(hdev);
1504
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001505 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001506 bool changed = false;
1507
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001508 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001509 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001510 changed = true;
1511 }
1512
1513 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1514 if (err < 0)
1515 goto failed;
1516
1517 if (changed)
1518 err = new_settings(hdev, sk);
1519
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001520 goto failed;
1521 }
1522
Johan Hedberg333ae952015-03-17 13:48:47 +02001523 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001524 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1525 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001526 goto failed;
1527 }
1528
1529 val = !!cp->val;
1530
1531 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1532 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1533 goto failed;
1534 }
1535
1536 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1537 if (!cmd) {
1538 err = -ENOMEM;
1539 goto failed;
1540 }
1541
1542 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1543 if (err < 0) {
1544 mgmt_pending_remove(cmd);
1545 goto failed;
1546 }
1547
1548failed:
1549 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001550 return err;
1551}
1552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001553static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001554{
1555 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001556 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001557 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001558 int err;
1559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001560 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001561
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001562 status = mgmt_bredr_support(hdev);
1563 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001564 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001565
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001566 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001567 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1568 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001569
Johan Hedberga7e80f22013-01-09 16:05:19 +02001570 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001571 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1572 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001573
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001574 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001575
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001576 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001577 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001578
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001579 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001580 changed = !hci_dev_test_and_set_flag(hdev,
1581 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001582 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001583 changed = hci_dev_test_and_clear_flag(hdev,
1584 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001585 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001586 changed = hci_dev_test_and_clear_flag(hdev,
1587 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001588 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001589 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001590 }
1591
1592 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1593 if (err < 0)
1594 goto failed;
1595
1596 if (changed)
1597 err = new_settings(hdev, sk);
1598
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001599 goto failed;
1600 }
1601
Johan Hedberg333ae952015-03-17 13:48:47 +02001602 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001603 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1604 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001605 goto failed;
1606 }
1607
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001608 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001609 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1610 goto failed;
1611 }
1612
1613 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1614 if (!cmd) {
1615 err = -ENOMEM;
1616 goto failed;
1617 }
1618
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001619 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001620 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1621 sizeof(cp->val), &cp->val);
1622
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001623 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001624 if (err < 0) {
1625 mgmt_pending_remove(cmd);
1626 goto failed;
1627 }
1628
1629failed:
1630 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001631 return err;
1632}
1633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001634static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001635{
1636 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001637 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001638 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001639 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001640
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001641 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001642
Johan Hedberge6fe7982013-10-02 15:45:22 +03001643 status = mgmt_bredr_support(hdev);
1644 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001645 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001646
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001647 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001648 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1649 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001650
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001651 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001652 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1653 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001654
Johan Hedberga7e80f22013-01-09 16:05:19 +02001655 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001656 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1657 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001658
Marcel Holtmannee392692013-10-01 22:59:23 -07001659 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001660
Johan Hedberg333ae952015-03-17 13:48:47 +02001661 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001662 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1663 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001664 goto unlock;
1665 }
1666
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001667 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001668 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001669 } else {
1670 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001671 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1672 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001673 goto unlock;
1674 }
1675
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001676 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001677 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001678
1679 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1680 if (err < 0)
1681 goto unlock;
1682
1683 if (changed)
1684 err = new_settings(hdev, sk);
1685
1686unlock:
1687 hci_dev_unlock(hdev);
1688 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001689}
1690
Marcel Holtmann1904a852015-01-11 13:50:44 -08001691static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001692{
1693 struct cmd_lookup match = { NULL, hdev };
1694
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301695 hci_dev_lock(hdev);
1696
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001697 if (status) {
1698 u8 mgmt_err = mgmt_status(status);
1699
1700 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1701 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301702 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001703 }
1704
1705 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1706
1707 new_settings(hdev, match.sk);
1708
1709 if (match.sk)
1710 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001711
1712 /* Make sure the controller has a good default for
1713 * advertising data. Restrict the update to when LE
1714 * has actually been enabled. During power on, the
1715 * update in powered_update_hci will take care of it.
1716 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001717 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001718 struct hci_request req;
1719
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001720 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001721 __hci_req_update_adv_data(&req, 0x00);
1722 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001723 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001724 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001725 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301726
1727unlock:
1728 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001729}
1730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001731static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001732{
1733 struct mgmt_mode *cp = data;
1734 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001735 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001736 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001737 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001738 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001739
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001740 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001741
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001742 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001743 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1744 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001745
Johan Hedberga7e80f22013-01-09 16:05:19 +02001746 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001747 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1748 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001749
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001750 /* Bluetooth single mode LE only controllers or dual-mode
1751 * controllers configured as LE only devices, do not allow
1752 * switching LE off. These have either LE enabled explicitly
1753 * or BR/EDR has been previously switched off.
1754 *
1755 * When trying to enable an already enabled LE, then gracefully
1756 * send a positive response. Trying to disable it however will
1757 * result into rejection.
1758 */
1759 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1760 if (cp->val == 0x01)
1761 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1762
Johan Hedberga69e8372015-03-06 21:08:53 +02001763 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1764 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001765 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001766
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001767 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001768
1769 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001770 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001771
Florian Grandel847818d2015-06-18 03:16:46 +02001772 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001773 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001774
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001775 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001776 bool changed = false;
1777
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001778 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001779 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001780 changed = true;
1781 }
1782
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001783 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001784 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001785 changed = true;
1786 }
1787
Johan Hedberg06199cf2012-02-22 16:37:11 +02001788 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1789 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001790 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001791
1792 if (changed)
1793 err = new_settings(hdev, sk);
1794
Johan Hedberg1de028c2012-02-29 19:55:35 -08001795 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001796 }
1797
Johan Hedberg333ae952015-03-17 13:48:47 +02001798 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1799 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001800 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1801 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001802 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001803 }
1804
1805 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1806 if (!cmd) {
1807 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001808 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001809 }
1810
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001811 hci_req_init(&req, hdev);
1812
Johan Hedberg06199cf2012-02-22 16:37:11 +02001813 memset(&hci_cp, 0, sizeof(hci_cp));
1814
1815 if (val) {
1816 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001817 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001818 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001819 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001820 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001821 }
1822
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001823 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1824 &hci_cp);
1825
1826 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301827 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001828 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001829
Johan Hedberg1de028c2012-02-29 19:55:35 -08001830unlock:
1831 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001832 return err;
1833}
1834
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001835/* This is a helper function to test for pending mgmt commands that can
1836 * cause CoD or EIR HCI commands. We can only allow one such pending
1837 * mgmt command at a time since otherwise we cannot easily track what
1838 * the current values are, will be, and based on that calculate if a new
1839 * HCI command needs to be sent and if yes with what value.
1840 */
1841static bool pending_eir_or_class(struct hci_dev *hdev)
1842{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001843 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001844
1845 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1846 switch (cmd->opcode) {
1847 case MGMT_OP_ADD_UUID:
1848 case MGMT_OP_REMOVE_UUID:
1849 case MGMT_OP_SET_DEV_CLASS:
1850 case MGMT_OP_SET_POWERED:
1851 return true;
1852 }
1853 }
1854
1855 return false;
1856}
1857
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001858static const u8 bluetooth_base_uuid[] = {
1859 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1860 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1861};
1862
1863static u8 get_uuid_size(const u8 *uuid)
1864{
1865 u32 val;
1866
1867 if (memcmp(uuid, bluetooth_base_uuid, 12))
1868 return 128;
1869
1870 val = get_unaligned_le32(&uuid[12]);
1871 if (val > 0xffff)
1872 return 32;
1873
1874 return 16;
1875}
1876
Johan Hedberg92da6092013-03-15 17:06:55 -05001877static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1878{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001879 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001880
1881 hci_dev_lock(hdev);
1882
Johan Hedberg333ae952015-03-17 13:48:47 +02001883 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001884 if (!cmd)
1885 goto unlock;
1886
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001887 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1888 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001889
1890 mgmt_pending_remove(cmd);
1891
1892unlock:
1893 hci_dev_unlock(hdev);
1894}
1895
Marcel Holtmann1904a852015-01-11 13:50:44 -08001896static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001897{
1898 BT_DBG("status 0x%02x", status);
1899
1900 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1901}
1902
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001903static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001904{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001905 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001906 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001907 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001908 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001909 int err;
1910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001911 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001913 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001914
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001915 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001916 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1917 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001918 goto failed;
1919 }
1920
Andre Guedes92c4c202012-06-07 19:05:44 -03001921 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001922 if (!uuid) {
1923 err = -ENOMEM;
1924 goto failed;
1925 }
1926
1927 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001928 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001929 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001930
Johan Hedbergde66aa62013-01-27 00:31:27 +02001931 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001932
Johan Hedberg890ea892013-03-15 17:06:52 -05001933 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001934
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001935 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001936 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001937
Johan Hedberg92da6092013-03-15 17:06:55 -05001938 err = hci_req_run(&req, add_uuid_complete);
1939 if (err < 0) {
1940 if (err != -ENODATA)
1941 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001942
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001943 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1944 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001945 goto failed;
1946 }
1947
1948 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001949 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001950 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001951 goto failed;
1952 }
1953
1954 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001955
1956failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001957 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001958 return err;
1959}
1960
Johan Hedberg24b78d02012-02-23 23:24:30 +02001961static bool enable_service_cache(struct hci_dev *hdev)
1962{
1963 if (!hdev_is_powered(hdev))
1964 return false;
1965
Marcel Holtmann238be782015-03-13 02:11:06 -07001966 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001967 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1968 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001969 return true;
1970 }
1971
1972 return false;
1973}
1974
Marcel Holtmann1904a852015-01-11 13:50:44 -08001975static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001976{
1977 BT_DBG("status 0x%02x", status);
1978
1979 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1980}
1981
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001983 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001984{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001985 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001986 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001987 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001988 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 -05001989 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001990 int err, found;
1991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001992 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001993
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001994 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001996 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001997 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1998 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001999 goto unlock;
2000 }
2001
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002002 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002003 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002004
Johan Hedberg24b78d02012-02-23 23:24:30 +02002005 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002006 err = mgmt_cmd_complete(sk, hdev->id,
2007 MGMT_OP_REMOVE_UUID,
2008 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002009 goto unlock;
2010 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002011
Johan Hedberg9246a862012-02-23 21:33:16 +02002012 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002013 }
2014
2015 found = 0;
2016
Johan Hedberg056341c2013-01-27 00:31:30 +02002017 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002018 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2019 continue;
2020
2021 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002022 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002023 found++;
2024 }
2025
2026 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002027 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2028 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002029 goto unlock;
2030 }
2031
Johan Hedberg9246a862012-02-23 21:33:16 +02002032update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002033 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002034
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002035 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002036 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002037
Johan Hedberg92da6092013-03-15 17:06:55 -05002038 err = hci_req_run(&req, remove_uuid_complete);
2039 if (err < 0) {
2040 if (err != -ENODATA)
2041 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002042
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002043 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2044 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002045 goto unlock;
2046 }
2047
2048 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002049 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002050 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002051 goto unlock;
2052 }
2053
2054 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055
2056unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002057 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002058 return err;
2059}
2060
Marcel Holtmann1904a852015-01-11 13:50:44 -08002061static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002062{
2063 BT_DBG("status 0x%02x", status);
2064
2065 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2066}
2067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002069 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002070{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002071 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002072 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002073 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002074 int err;
2075
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002076 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002077
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002078 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002079 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2080 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002082 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002083
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002084 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002085 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2086 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002087 goto unlock;
2088 }
2089
2090 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002091 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2092 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002093 goto unlock;
2094 }
2095
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002096 hdev->major_class = cp->major;
2097 hdev->minor_class = cp->minor;
2098
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002099 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002100 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2101 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002102 goto unlock;
2103 }
2104
Johan Hedberg890ea892013-03-15 17:06:52 -05002105 hci_req_init(&req, hdev);
2106
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002107 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002108 hci_dev_unlock(hdev);
2109 cancel_delayed_work_sync(&hdev->service_cache);
2110 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002111 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002112 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002113
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002114 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002115
Johan Hedberg92da6092013-03-15 17:06:55 -05002116 err = hci_req_run(&req, set_class_complete);
2117 if (err < 0) {
2118 if (err != -ENODATA)
2119 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002120
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002121 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2122 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002123 goto unlock;
2124 }
2125
2126 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002127 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002128 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002129 goto unlock;
2130 }
2131
2132 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002133
Johan Hedbergb5235a62012-02-21 14:32:24 +02002134unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002136 return err;
2137}
2138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002139static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002140 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002142 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002143 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2144 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002145 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002146 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002147 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002148
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002149 BT_DBG("request for %s", hdev->name);
2150
2151 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002152 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2153 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002154
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002155 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002156 if (key_count > max_key_count) {
2157 BT_ERR("load_link_keys: too big key_count value %u",
2158 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002159 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2160 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002161 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002162
Johan Hedberg86742e12011-11-07 23:13:38 +02002163 expected_len = sizeof(*cp) + key_count *
2164 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002165 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002166 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002167 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002168 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2169 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002170 }
2171
Johan Hedberg4ae143012013-01-20 14:27:13 +02002172 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002173 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2174 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002176 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002177 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002178
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002179 for (i = 0; i < key_count; i++) {
2180 struct mgmt_link_key_info *key = &cp->keys[i];
2181
Marcel Holtmann8e991132014-01-10 02:07:25 -08002182 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002183 return mgmt_cmd_status(sk, hdev->id,
2184 MGMT_OP_LOAD_LINK_KEYS,
2185 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002186 }
2187
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002188 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002189
2190 hci_link_keys_clear(hdev);
2191
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002192 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002193 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002194 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002195 changed = hci_dev_test_and_clear_flag(hdev,
2196 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002197
2198 if (changed)
2199 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002200
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002201 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002202 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002203
Johan Hedberg58e92932014-06-24 14:00:26 +03002204 /* Always ignore debug keys and require a new pairing if
2205 * the user wants to use them.
2206 */
2207 if (key->type == HCI_LK_DEBUG_COMBINATION)
2208 continue;
2209
Johan Hedberg7652ff62014-06-24 13:15:49 +03002210 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2211 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002212 }
2213
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002214 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002217
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002218 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002219}
2220
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002221static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002222 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002223{
2224 struct mgmt_ev_device_unpaired ev;
2225
2226 bacpy(&ev.addr.bdaddr, bdaddr);
2227 ev.addr.type = addr_type;
2228
2229 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002230 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002231}
2232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002233static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002234 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002235{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002236 struct mgmt_cp_unpair_device *cp = data;
2237 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002238 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002239 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002240 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002241 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002242 int err;
2243
Johan Hedberga8a1d192011-11-10 15:54:38 +02002244 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002245 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2246 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002247
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002248 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002249 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2250 MGMT_STATUS_INVALID_PARAMS,
2251 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002252
Johan Hedberg118da702013-01-20 14:27:20 +02002253 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002254 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2255 MGMT_STATUS_INVALID_PARAMS,
2256 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002257
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002258 hci_dev_lock(hdev);
2259
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002260 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002261 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2262 MGMT_STATUS_NOT_POWERED, &rp,
2263 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002264 goto unlock;
2265 }
2266
Johan Hedberge0b2b272014-02-18 17:14:31 +02002267 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002268 /* If disconnection is requested, then look up the
2269 * connection. If the remote device is connected, it
2270 * will be later used to terminate the link.
2271 *
2272 * Setting it to NULL explicitly will cause no
2273 * termination of the link.
2274 */
2275 if (cp->disconnect)
2276 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2277 &cp->addr.bdaddr);
2278 else
2279 conn = NULL;
2280
Johan Hedberg124f6e32012-02-09 13:50:12 +02002281 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002282 if (err < 0) {
2283 err = mgmt_cmd_complete(sk, hdev->id,
2284 MGMT_OP_UNPAIR_DEVICE,
2285 MGMT_STATUS_NOT_PAIRED, &rp,
2286 sizeof(rp));
2287 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002288 }
2289
Johan Hedbergec182f02015-10-21 18:03:03 +03002290 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002291 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002292
Johan Hedbergec182f02015-10-21 18:03:03 +03002293 /* LE address type */
2294 addr_type = le_addr_type(cp->addr.type);
2295
2296 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2297
2298 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002299 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002300 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2301 MGMT_STATUS_NOT_PAIRED, &rp,
2302 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002303 goto unlock;
2304 }
2305
Johan Hedbergec182f02015-10-21 18:03:03 +03002306 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2307 if (!conn) {
2308 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2309 goto done;
2310 }
2311
Johan Hedbergc81d5552015-10-22 09:38:35 +03002312 /* Abort any ongoing SMP pairing */
2313 smp_cancel_pairing(conn);
2314
Johan Hedbergec182f02015-10-21 18:03:03 +03002315 /* Defer clearing up the connection parameters until closing to
2316 * give a chance of keeping them if a repairing happens.
2317 */
2318 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2319
Johan Hedbergfc643612015-10-22 09:38:31 +03002320 /* Disable auto-connection parameters if present */
2321 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2322 if (params) {
2323 if (params->explicit_connect)
2324 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2325 else
2326 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2327 }
2328
Johan Hedbergec182f02015-10-21 18:03:03 +03002329 /* If disconnection is not requested, then clear the connection
2330 * variable so that the link is not terminated.
2331 */
2332 if (!cp->disconnect)
2333 conn = NULL;
2334
2335done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002336 /* If the connection variable is set, then termination of the
2337 * link is requested.
2338 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002339 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002340 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2341 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002342 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002343 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344 }
2345
Johan Hedberg124f6e32012-02-09 13:50:12 +02002346 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002347 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002348 if (!cmd) {
2349 err = -ENOMEM;
2350 goto unlock;
2351 }
2352
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002353 cmd->cmd_complete = addr_cmd_complete;
2354
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002355 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002356 if (err < 0)
2357 mgmt_pending_remove(cmd);
2358
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002359unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002360 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002361 return err;
2362}
2363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002364static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002365 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002366{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002367 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002368 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002369 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002370 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371 int err;
2372
2373 BT_DBG("");
2374
Johan Hedberg06a63b12013-01-20 14:27:21 +02002375 memset(&rp, 0, sizeof(rp));
2376 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2377 rp.addr.type = cp->addr.type;
2378
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002379 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002380 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2381 MGMT_STATUS_INVALID_PARAMS,
2382 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002385
2386 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002387 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2388 MGMT_STATUS_NOT_POWERED, &rp,
2389 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002390 goto failed;
2391 }
2392
Johan Hedberg333ae952015-03-17 13:48:47 +02002393 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002394 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2395 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002396 goto failed;
2397 }
2398
Andre Guedes591f47f2012-04-24 21:02:49 -03002399 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002400 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2401 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002402 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002403 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2404 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002405
Vishal Agarwalf9607272012-06-13 05:32:43 +05302406 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002407 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2408 MGMT_STATUS_NOT_CONNECTED, &rp,
2409 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002410 goto failed;
2411 }
2412
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002413 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002414 if (!cmd) {
2415 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002416 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002417 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418
Johan Hedbergf5818c22014-12-05 13:36:02 +02002419 cmd->cmd_complete = generic_cmd_complete;
2420
Johan Hedberge3f2f922014-08-18 20:33:33 +03002421 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002422 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002423 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002424
2425failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002426 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002427 return err;
2428}
2429
Andre Guedes57c14772012-04-24 21:02:50 -03002430static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002431{
2432 switch (link_type) {
2433 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002434 switch (addr_type) {
2435 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002436 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002437
Johan Hedberg48264f02011-11-09 13:58:58 +02002438 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002439 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002440 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002441 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002442
Johan Hedberg4c659c32011-11-07 23:13:39 +02002443 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002444 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002445 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002446 }
2447}
2448
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002449static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2450 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002451{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002452 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002453 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002454 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002455 int err;
2456 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002457
2458 BT_DBG("");
2459
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002460 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002461
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002462 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002463 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2464 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002465 goto unlock;
2466 }
2467
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002468 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002469 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2470 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002471 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002472 }
2473
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002474 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002475 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002476 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002477 err = -ENOMEM;
2478 goto unlock;
2479 }
2480
Johan Hedberg2784eb42011-01-21 13:56:35 +02002481 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002482 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002483 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2484 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002485 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002486 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002487 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002488 continue;
2489 i++;
2490 }
2491
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002492 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002493
Johan Hedberg4c659c32011-11-07 23:13:39 +02002494 /* Recalculate length in case of filtered SCO connections, etc */
2495 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002496
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002497 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2498 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002499
Johan Hedberga38528f2011-01-22 06:46:43 +02002500 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002501
2502unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002503 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002504 return err;
2505}
2506
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002507static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002508 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002509{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002510 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002511 int err;
2512
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002513 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002514 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002515 if (!cmd)
2516 return -ENOMEM;
2517
Johan Hedbergd8457692012-02-17 14:24:57 +02002518 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002519 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002520 if (err < 0)
2521 mgmt_pending_remove(cmd);
2522
2523 return err;
2524}
2525
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002526static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002527 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002528{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002529 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002530 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002531 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002532 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533 int err;
2534
2535 BT_DBG("");
2536
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002537 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002538
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002539 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002540 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2541 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002542 goto failed;
2543 }
2544
Johan Hedbergd8457692012-02-17 14:24:57 +02002545 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002546 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002547 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2548 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002549 goto failed;
2550 }
2551
2552 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002553 struct mgmt_cp_pin_code_neg_reply ncp;
2554
2555 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002556
2557 BT_ERR("PIN code is not 16 bytes long");
2558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002559 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002560 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002561 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2562 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002563
2564 goto failed;
2565 }
2566
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002567 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002568 if (!cmd) {
2569 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002570 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002571 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002572
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002573 cmd->cmd_complete = addr_cmd_complete;
2574
Johan Hedbergd8457692012-02-17 14:24:57 +02002575 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002576 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002577 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002578
2579 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2580 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002581 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002582
2583failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002584 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002585 return err;
2586}
2587
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2589 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002590{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002591 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002592
2593 BT_DBG("");
2594
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002595 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002596 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2597 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002598
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002600
2601 hdev->io_capability = cp->io_capability;
2602
2603 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002604 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002605
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002606 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002607
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002608 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2609 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002610}
2611
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002612static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002613{
2614 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002615 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002616
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002617 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002618 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2619 continue;
2620
Johan Hedberge9a416b2011-02-19 12:05:56 -03002621 if (cmd->user_data != conn)
2622 continue;
2623
2624 return cmd;
2625 }
2626
2627 return NULL;
2628}
2629
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002630static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002631{
2632 struct mgmt_rp_pair_device rp;
2633 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002634 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002635
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002636 bacpy(&rp.addr.bdaddr, &conn->dst);
2637 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002638
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002639 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2640 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641
2642 /* So we don't get further callbacks for this connection */
2643 conn->connect_cfm_cb = NULL;
2644 conn->security_cfm_cb = NULL;
2645 conn->disconn_cfm_cb = NULL;
2646
David Herrmann76a68ba2013-04-06 20:28:37 +02002647 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002648
2649 /* The device is paired so there is no need to remove
2650 * its connection parameters anymore.
2651 */
2652 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002653
2654 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002655
2656 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002657}
2658
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002659void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2660{
2661 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002662 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002663
2664 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002665 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002666 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002667 mgmt_pending_remove(cmd);
2668 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002669}
2670
Johan Hedberge9a416b2011-02-19 12:05:56 -03002671static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2672{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002673 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002674
2675 BT_DBG("status %u", status);
2676
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002677 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002678 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002679 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002680 return;
2681 }
2682
2683 cmd->cmd_complete(cmd, mgmt_status(status));
2684 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002685}
2686
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002687static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302688{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002689 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302690
2691 BT_DBG("status %u", status);
2692
2693 if (!status)
2694 return;
2695
2696 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002697 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302698 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002699 return;
2700 }
2701
2702 cmd->cmd_complete(cmd, mgmt_status(status));
2703 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302704}
2705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002706static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002707 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002708{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002709 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002710 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002711 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002712 u8 sec_level, auth_type;
2713 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002714 int err;
2715
2716 BT_DBG("");
2717
Szymon Jancf950a30e2013-01-18 12:48:07 +01002718 memset(&rp, 0, sizeof(rp));
2719 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2720 rp.addr.type = cp->addr.type;
2721
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002722 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002723 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2724 MGMT_STATUS_INVALID_PARAMS,
2725 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002726
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002727 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002728 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2729 MGMT_STATUS_INVALID_PARAMS,
2730 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002732 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002733
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002734 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002735 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2736 MGMT_STATUS_NOT_POWERED, &rp,
2737 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002738 goto unlock;
2739 }
2740
Johan Hedberg55e76b32015-03-10 22:34:40 +02002741 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2742 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2743 MGMT_STATUS_ALREADY_PAIRED, &rp,
2744 sizeof(rp));
2745 goto unlock;
2746 }
2747
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002748 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002749 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002750
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002751 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002752 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2753 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002754 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002755 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002756 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002757
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002758 /* When pairing a new device, it is expected to remember
2759 * this device for future connections. Adding the connection
2760 * parameter information ahead of time allows tracking
2761 * of the slave preferred values and will speed up any
2762 * further connection establishment.
2763 *
2764 * If connection parameters already exist, then they
2765 * will be kept and this function does nothing.
2766 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002767 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2768
2769 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2770 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002771
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002772 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2773 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002774 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002775 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002776
Ville Tervo30e76272011-02-22 16:10:53 -03002777 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002778 int status;
2779
2780 if (PTR_ERR(conn) == -EBUSY)
2781 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002782 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2783 status = MGMT_STATUS_NOT_SUPPORTED;
2784 else if (PTR_ERR(conn) == -ECONNREFUSED)
2785 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002786 else
2787 status = MGMT_STATUS_CONNECT_FAILED;
2788
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002789 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2790 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002791 goto unlock;
2792 }
2793
2794 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002795 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002796 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2797 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002798 goto unlock;
2799 }
2800
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002801 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002802 if (!cmd) {
2803 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002804 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002805 goto unlock;
2806 }
2807
Johan Hedberg04ab2742014-12-05 13:36:04 +02002808 cmd->cmd_complete = pairing_complete;
2809
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002810 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002811 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002812 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002813 conn->security_cfm_cb = pairing_complete_cb;
2814 conn->disconn_cfm_cb = pairing_complete_cb;
2815 } else {
2816 conn->connect_cfm_cb = le_pairing_complete_cb;
2817 conn->security_cfm_cb = le_pairing_complete_cb;
2818 conn->disconn_cfm_cb = le_pairing_complete_cb;
2819 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002820
Johan Hedberge9a416b2011-02-19 12:05:56 -03002821 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002822 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002823
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002824 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002825 hci_conn_security(conn, sec_level, auth_type, true)) {
2826 cmd->cmd_complete(cmd, 0);
2827 mgmt_pending_remove(cmd);
2828 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002829
2830 err = 0;
2831
2832unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002833 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002834 return err;
2835}
2836
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002837static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2838 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002839{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002840 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002841 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002842 struct hci_conn *conn;
2843 int err;
2844
2845 BT_DBG("");
2846
Johan Hedberg28424702012-02-02 04:02:29 +02002847 hci_dev_lock(hdev);
2848
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002849 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002850 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2851 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002852 goto unlock;
2853 }
2854
Johan Hedberg333ae952015-03-17 13:48:47 +02002855 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002856 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002857 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2858 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002859 goto unlock;
2860 }
2861
2862 conn = cmd->user_data;
2863
2864 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002865 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2866 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002867 goto unlock;
2868 }
2869
Johan Hedberga511b352014-12-11 21:45:45 +02002870 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2871 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002872
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002873 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2874 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002875unlock:
2876 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002877 return err;
2878}
2879
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002880static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002881 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002882 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002883{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002884 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002885 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002886 int err;
2887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002888 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002889
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002890 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002891 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2892 MGMT_STATUS_NOT_POWERED, addr,
2893 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002894 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002895 }
2896
Johan Hedberg1707c602013-03-15 17:07:15 -05002897 if (addr->type == BDADDR_BREDR)
2898 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002899 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002900 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2901 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002902
Johan Hedberg272d90d2012-02-09 15:26:12 +02002903 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002904 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2905 MGMT_STATUS_NOT_CONNECTED, addr,
2906 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002907 goto done;
2908 }
2909
Johan Hedberg1707c602013-03-15 17:07:15 -05002910 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002911 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002912 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002913 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2914 MGMT_STATUS_SUCCESS, addr,
2915 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002916 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002917 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2918 MGMT_STATUS_FAILED, addr,
2919 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002920
Brian Gix47c15e22011-11-16 13:53:14 -08002921 goto done;
2922 }
2923
Johan Hedberg1707c602013-03-15 17:07:15 -05002924 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002925 if (!cmd) {
2926 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002927 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002928 }
2929
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002930 cmd->cmd_complete = addr_cmd_complete;
2931
Brian Gix0df4c182011-11-16 13:53:13 -08002932 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002933 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2934 struct hci_cp_user_passkey_reply cp;
2935
Johan Hedberg1707c602013-03-15 17:07:15 -05002936 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002937 cp.passkey = passkey;
2938 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2939 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002940 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2941 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002942
Johan Hedberga664b5b2011-02-19 12:06:02 -03002943 if (err < 0)
2944 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002945
Brian Gix0df4c182011-11-16 13:53:13 -08002946done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002947 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002948 return err;
2949}
2950
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302951static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2952 void *data, u16 len)
2953{
2954 struct mgmt_cp_pin_code_neg_reply *cp = data;
2955
2956 BT_DBG("");
2957
Johan Hedberg1707c602013-03-15 17:07:15 -05002958 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302959 MGMT_OP_PIN_CODE_NEG_REPLY,
2960 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2961}
2962
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002963static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2964 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002965{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002966 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002967
2968 BT_DBG("");
2969
2970 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002971 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2972 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002973
Johan Hedberg1707c602013-03-15 17:07:15 -05002974 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002975 MGMT_OP_USER_CONFIRM_REPLY,
2976 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002977}
2978
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002979static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002980 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002981{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002982 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002983
2984 BT_DBG("");
2985
Johan Hedberg1707c602013-03-15 17:07:15 -05002986 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002987 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2988 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002989}
2990
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002991static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2992 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002993{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002994 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002995
2996 BT_DBG("");
2997
Johan Hedberg1707c602013-03-15 17:07:15 -05002998 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002999 MGMT_OP_USER_PASSKEY_REPLY,
3000 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003001}
3002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003003static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003004 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003005{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003006 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003007
3008 BT_DBG("");
3009
Johan Hedberg1707c602013-03-15 17:07:15 -05003010 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3012 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003013}
3014
Michał Narajowski7c295c42016-09-18 12:50:02 +02003015static void adv_expire(struct hci_dev *hdev, u32 flags)
3016{
3017 struct adv_info *adv_instance;
3018 struct hci_request req;
3019 int err;
3020
3021 adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
3022 if (!adv_instance)
3023 return;
3024
3025 /* stop if current instance doesn't need to be changed */
3026 if (!(adv_instance->flags & flags))
3027 return;
3028
3029 cancel_adv_timeout(hdev);
3030
3031 adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
3032 if (!adv_instance)
3033 return;
3034
3035 hci_req_init(&req, hdev);
3036 err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
3037 true);
3038 if (err)
3039 return;
3040
3041 hci_req_run(&req, NULL);
3042}
3043
Marcel Holtmann1904a852015-01-11 13:50:44 -08003044static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003045{
3046 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003047 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003048
3049 BT_DBG("status 0x%02x", status);
3050
3051 hci_dev_lock(hdev);
3052
Johan Hedberg333ae952015-03-17 13:48:47 +02003053 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003054 if (!cmd)
3055 goto unlock;
3056
3057 cp = cmd->param;
3058
Michał Narajowski7c295c42016-09-18 12:50:02 +02003059 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003060 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3061 mgmt_status(status));
Michał Narajowski7c295c42016-09-18 12:50:02 +02003062 } else {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003063 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3064 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003065
Michał Narajowski7c295c42016-09-18 12:50:02 +02003066 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
3067 adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
3068 }
3069
Johan Hedberg13928972013-03-15 17:07:00 -05003070 mgmt_pending_remove(cmd);
3071
3072unlock:
3073 hci_dev_unlock(hdev);
3074}
3075
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003076static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003077 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003078{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003079 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003080 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003081 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003082 int err;
3083
3084 BT_DBG("");
3085
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003086 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003087
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003088 /* If the old values are the same as the new ones just return a
3089 * direct command complete event.
3090 */
3091 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3092 !memcmp(hdev->short_name, cp->short_name,
3093 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003094 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3095 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003096 goto failed;
3097 }
3098
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003099 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003100
Johan Hedbergb5235a62012-02-21 14:32:24 +02003101 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003102 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003103
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003104 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3105 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003106 if (err < 0)
3107 goto failed;
3108
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003109 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3110 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003111 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003112
Johan Hedbergb5235a62012-02-21 14:32:24 +02003113 goto failed;
3114 }
3115
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003116 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003117 if (!cmd) {
3118 err = -ENOMEM;
3119 goto failed;
3120 }
3121
Johan Hedberg13928972013-03-15 17:07:00 -05003122 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3123
Johan Hedberg890ea892013-03-15 17:06:52 -05003124 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003125
3126 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003127 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003128 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003129 }
3130
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003131 /* The name is stored in the scan response data and so
3132 * no need to udpate the advertising data here.
3133 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003134 if (lmp_le_capable(hdev))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003135 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003136
Johan Hedberg13928972013-03-15 17:07:00 -05003137 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003138 if (err < 0)
3139 mgmt_pending_remove(cmd);
3140
3141failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003142 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003143 return err;
3144}
3145
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003146static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3147 u16 opcode, struct sk_buff *skb)
3148{
3149 struct mgmt_rp_read_local_oob_data mgmt_rp;
3150 size_t rp_size = sizeof(mgmt_rp);
3151 struct mgmt_pending_cmd *cmd;
3152
3153 BT_DBG("%s status %u", hdev->name, status);
3154
3155 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3156 if (!cmd)
3157 return;
3158
3159 if (status || !skb) {
3160 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3161 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3162 goto remove;
3163 }
3164
3165 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3166
3167 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3168 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3169
3170 if (skb->len < sizeof(*rp)) {
3171 mgmt_cmd_status(cmd->sk, hdev->id,
3172 MGMT_OP_READ_LOCAL_OOB_DATA,
3173 MGMT_STATUS_FAILED);
3174 goto remove;
3175 }
3176
3177 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3178 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3179
3180 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3181 } else {
3182 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3183
3184 if (skb->len < sizeof(*rp)) {
3185 mgmt_cmd_status(cmd->sk, hdev->id,
3186 MGMT_OP_READ_LOCAL_OOB_DATA,
3187 MGMT_STATUS_FAILED);
3188 goto remove;
3189 }
3190
3191 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3192 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3193
3194 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3195 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3196 }
3197
3198 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3199 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3200
3201remove:
3202 mgmt_pending_remove(cmd);
3203}
3204
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003205static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003207{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003208 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003209 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003210 int err;
3211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003212 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003214 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003215
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003216 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003217 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3218 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003219 goto unlock;
3220 }
3221
Andre Guedes9a1a1992012-07-24 15:03:48 -03003222 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003223 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3224 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003225 goto unlock;
3226 }
3227
Johan Hedberg333ae952015-03-17 13:48:47 +02003228 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003229 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3230 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003231 goto unlock;
3232 }
3233
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003234 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003235 if (!cmd) {
3236 err = -ENOMEM;
3237 goto unlock;
3238 }
3239
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003240 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003241
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003242 if (bredr_sc_enabled(hdev))
3243 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3244 else
3245 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3246
3247 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003248 if (err < 0)
3249 mgmt_pending_remove(cmd);
3250
3251unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003252 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003253 return err;
3254}
3255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003256static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003257 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003258{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003259 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003260 int err;
3261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003262 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003263
Johan Hedberg5d57e792015-01-23 10:10:38 +02003264 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003265 return mgmt_cmd_complete(sk, hdev->id,
3266 MGMT_OP_ADD_REMOTE_OOB_DATA,
3267 MGMT_STATUS_INVALID_PARAMS,
3268 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003269
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003270 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003271
Marcel Holtmannec109112014-01-10 02:07:30 -08003272 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3273 struct mgmt_cp_add_remote_oob_data *cp = data;
3274 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003275
Johan Hedbergc19a4952014-11-17 20:52:19 +02003276 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003277 err = mgmt_cmd_complete(sk, hdev->id,
3278 MGMT_OP_ADD_REMOTE_OOB_DATA,
3279 MGMT_STATUS_INVALID_PARAMS,
3280 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003281 goto unlock;
3282 }
3283
Marcel Holtmannec109112014-01-10 02:07:30 -08003284 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003285 cp->addr.type, cp->hash,
3286 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003287 if (err < 0)
3288 status = MGMT_STATUS_FAILED;
3289 else
3290 status = MGMT_STATUS_SUCCESS;
3291
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003292 err = mgmt_cmd_complete(sk, hdev->id,
3293 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3294 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003295 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3296 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003297 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003298 u8 status;
3299
Johan Hedberg86df9202014-10-26 20:52:27 +01003300 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003301 /* Enforce zero-valued 192-bit parameters as
3302 * long as legacy SMP OOB isn't implemented.
3303 */
3304 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3305 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003306 err = mgmt_cmd_complete(sk, hdev->id,
3307 MGMT_OP_ADD_REMOTE_OOB_DATA,
3308 MGMT_STATUS_INVALID_PARAMS,
3309 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003310 goto unlock;
3311 }
3312
Johan Hedberg86df9202014-10-26 20:52:27 +01003313 rand192 = NULL;
3314 hash192 = NULL;
3315 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003316 /* In case one of the P-192 values is set to zero,
3317 * then just disable OOB data for P-192.
3318 */
3319 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3320 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3321 rand192 = NULL;
3322 hash192 = NULL;
3323 } else {
3324 rand192 = cp->rand192;
3325 hash192 = cp->hash192;
3326 }
3327 }
3328
3329 /* In case one of the P-256 values is set to zero, then just
3330 * disable OOB data for P-256.
3331 */
3332 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3333 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3334 rand256 = NULL;
3335 hash256 = NULL;
3336 } else {
3337 rand256 = cp->rand256;
3338 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003339 }
3340
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003341 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003342 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003343 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003344 if (err < 0)
3345 status = MGMT_STATUS_FAILED;
3346 else
3347 status = MGMT_STATUS_SUCCESS;
3348
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003349 err = mgmt_cmd_complete(sk, hdev->id,
3350 MGMT_OP_ADD_REMOTE_OOB_DATA,
3351 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003352 } else {
3353 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003354 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3355 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003356 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003357
Johan Hedbergc19a4952014-11-17 20:52:19 +02003358unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003359 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003360 return err;
3361}
3362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003363static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003364 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003365{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003366 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003367 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003368 int err;
3369
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003370 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003371
Johan Hedbergc19a4952014-11-17 20:52:19 +02003372 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003373 return mgmt_cmd_complete(sk, hdev->id,
3374 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3375 MGMT_STATUS_INVALID_PARAMS,
3376 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003377
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003378 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003379
Johan Hedbergeedbd582014-11-15 09:34:23 +02003380 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3381 hci_remote_oob_data_clear(hdev);
3382 status = MGMT_STATUS_SUCCESS;
3383 goto done;
3384 }
3385
Johan Hedberg6928a922014-10-26 20:46:09 +01003386 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003387 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003388 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003389 else
Szymon Janca6785be2012-12-13 15:11:21 +01003390 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003391
Johan Hedbergeedbd582014-11-15 09:34:23 +02003392done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003393 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3394 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003395
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003396 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003397 return err;
3398}
3399
Johan Hedberge68f0722015-11-11 08:30:30 +02003400void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003401{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003402 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003403
Andre Guedes7c307722013-04-30 15:29:28 -03003404 BT_DBG("status %d", status);
3405
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003406 hci_dev_lock(hdev);
3407
Johan Hedberg333ae952015-03-17 13:48:47 +02003408 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003409 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003410 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003411
Johan Hedberg78b781c2016-01-05 13:19:32 +02003412 if (!cmd)
3413 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3414
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003415 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003416 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003417 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003418 }
3419
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003420 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003421}
3422
Johan Hedberg591752a2015-11-11 08:11:24 +02003423static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3424 uint8_t *mgmt_status)
3425{
3426 switch (type) {
3427 case DISCOV_TYPE_LE:
3428 *mgmt_status = mgmt_le_support(hdev);
3429 if (*mgmt_status)
3430 return false;
3431 break;
3432 case DISCOV_TYPE_INTERLEAVED:
3433 *mgmt_status = mgmt_le_support(hdev);
3434 if (*mgmt_status)
3435 return false;
3436 /* Intentional fall-through */
3437 case DISCOV_TYPE_BREDR:
3438 *mgmt_status = mgmt_bredr_support(hdev);
3439 if (*mgmt_status)
3440 return false;
3441 break;
3442 default:
3443 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3444 return false;
3445 }
3446
3447 return true;
3448}
3449
Johan Hedberg78b781c2016-01-05 13:19:32 +02003450static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3451 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003452{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003453 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003454 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003455 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003456 int err;
3457
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003458 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003459
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003460 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003461
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003462 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003463 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003464 MGMT_STATUS_NOT_POWERED,
3465 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003466 goto failed;
3467 }
3468
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003469 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003470 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003471 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3472 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003473 goto failed;
3474 }
3475
Johan Hedberg591752a2015-11-11 08:11:24 +02003476 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003477 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3478 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003479 goto failed;
3480 }
3481
Marcel Holtmann22078802014-12-05 11:45:22 +01003482 /* Clear the discovery filter first to free any previously
3483 * allocated memory for the UUID list.
3484 */
3485 hci_discovery_filter_clear(hdev);
3486
Andre Guedes4aab14e2012-02-17 20:39:36 -03003487 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003488 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003489 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3490 hdev->discovery.limited = true;
3491 else
3492 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003493
Johan Hedberg78b781c2016-01-05 13:19:32 +02003494 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003495 if (!cmd) {
3496 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003497 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003498 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003499
Johan Hedberge68f0722015-11-11 08:30:30 +02003500 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003501
3502 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003503 queue_work(hdev->req_workqueue, &hdev->discov_update);
3504 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003505
3506failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003507 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003508 return err;
3509}
3510
Johan Hedberg78b781c2016-01-05 13:19:32 +02003511static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3512 void *data, u16 len)
3513{
3514 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3515 data, len);
3516}
3517
3518static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3519 void *data, u16 len)
3520{
3521 return start_discovery_internal(sk, hdev,
3522 MGMT_OP_START_LIMITED_DISCOVERY,
3523 data, len);
3524}
3525
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003526static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3527 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003528{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003529 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3530 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003531}
3532
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003533static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3534 void *data, u16 len)
3535{
3536 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003537 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003538 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3539 u16 uuid_count, expected_len;
3540 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003541 int err;
3542
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003543 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003544
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003545 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003546
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003547 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003548 err = mgmt_cmd_complete(sk, hdev->id,
3549 MGMT_OP_START_SERVICE_DISCOVERY,
3550 MGMT_STATUS_NOT_POWERED,
3551 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003552 goto failed;
3553 }
3554
3555 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003556 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003557 err = mgmt_cmd_complete(sk, hdev->id,
3558 MGMT_OP_START_SERVICE_DISCOVERY,
3559 MGMT_STATUS_BUSY, &cp->type,
3560 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003561 goto failed;
3562 }
3563
3564 uuid_count = __le16_to_cpu(cp->uuid_count);
3565 if (uuid_count > max_uuid_count) {
3566 BT_ERR("service_discovery: too big uuid_count value %u",
3567 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003568 err = mgmt_cmd_complete(sk, hdev->id,
3569 MGMT_OP_START_SERVICE_DISCOVERY,
3570 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3571 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003572 goto failed;
3573 }
3574
3575 expected_len = sizeof(*cp) + uuid_count * 16;
3576 if (expected_len != len) {
3577 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3578 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003579 err = mgmt_cmd_complete(sk, hdev->id,
3580 MGMT_OP_START_SERVICE_DISCOVERY,
3581 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3582 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003583 goto failed;
3584 }
3585
Johan Hedberg591752a2015-11-11 08:11:24 +02003586 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3587 err = mgmt_cmd_complete(sk, hdev->id,
3588 MGMT_OP_START_SERVICE_DISCOVERY,
3589 status, &cp->type, sizeof(cp->type));
3590 goto failed;
3591 }
3592
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003593 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003594 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003595 if (!cmd) {
3596 err = -ENOMEM;
3597 goto failed;
3598 }
3599
Johan Hedberg2922a942014-12-05 13:36:06 +02003600 cmd->cmd_complete = service_discovery_cmd_complete;
3601
Marcel Holtmann22078802014-12-05 11:45:22 +01003602 /* Clear the discovery filter first to free any previously
3603 * allocated memory for the UUID list.
3604 */
3605 hci_discovery_filter_clear(hdev);
3606
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003607 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003608 hdev->discovery.type = cp->type;
3609 hdev->discovery.rssi = cp->rssi;
3610 hdev->discovery.uuid_count = uuid_count;
3611
3612 if (uuid_count > 0) {
3613 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3614 GFP_KERNEL);
3615 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003616 err = mgmt_cmd_complete(sk, hdev->id,
3617 MGMT_OP_START_SERVICE_DISCOVERY,
3618 MGMT_STATUS_FAILED,
3619 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003620 mgmt_pending_remove(cmd);
3621 goto failed;
3622 }
3623 }
3624
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003625 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003626 queue_work(hdev->req_workqueue, &hdev->discov_update);
3627 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003628
3629failed:
3630 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003631 return err;
3632}
3633
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003634void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003635{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003636 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003637
Andre Guedes0e05bba2013-04-30 15:29:33 -03003638 BT_DBG("status %d", status);
3639
3640 hci_dev_lock(hdev);
3641
Johan Hedberg333ae952015-03-17 13:48:47 +02003642 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003643 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003644 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003645 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003646 }
3647
Andre Guedes0e05bba2013-04-30 15:29:33 -03003648 hci_dev_unlock(hdev);
3649}
3650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003651static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003652 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003653{
Johan Hedbergd9306502012-02-20 23:25:18 +02003654 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003655 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003656 int err;
3657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003658 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003660 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003661
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003662 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003663 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3664 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3665 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003666 goto unlock;
3667 }
3668
3669 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003670 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3671 MGMT_STATUS_INVALID_PARAMS,
3672 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003673 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003674 }
3675
Johan Hedberg2922a942014-12-05 13:36:06 +02003676 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003677 if (!cmd) {
3678 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003679 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003680 }
3681
Johan Hedberg2922a942014-12-05 13:36:06 +02003682 cmd->cmd_complete = generic_cmd_complete;
3683
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003684 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3685 queue_work(hdev->req_workqueue, &hdev->discov_update);
3686 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003687
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003688unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003689 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003690 return err;
3691}
3692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003693static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003694 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003695{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003696 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003697 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003698 int err;
3699
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003700 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003701
Johan Hedberg561aafb2012-01-04 13:31:59 +02003702 hci_dev_lock(hdev);
3703
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003704 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003705 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3706 MGMT_STATUS_FAILED, &cp->addr,
3707 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003708 goto failed;
3709 }
3710
Johan Hedberga198e7b2012-02-17 14:27:06 +02003711 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003712 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003713 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3714 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3715 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003716 goto failed;
3717 }
3718
3719 if (cp->name_known) {
3720 e->name_state = NAME_KNOWN;
3721 list_del(&e->list);
3722 } else {
3723 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003724 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003725 }
3726
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003727 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3728 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003729
3730failed:
3731 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003732 return err;
3733}
3734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003735static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003736 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003737{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003738 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003739 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003740 int err;
3741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003742 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003743
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003744 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003745 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3746 MGMT_STATUS_INVALID_PARAMS,
3747 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003748
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003749 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003750
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003751 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3752 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003753 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003754 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003755 goto done;
3756 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003757
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003758 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3759 sk);
3760 status = MGMT_STATUS_SUCCESS;
3761
3762done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003763 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3764 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003765
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003766 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003767
3768 return err;
3769}
3770
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003771static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003772 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003773{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003774 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003775 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003776 int err;
3777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003778 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003779
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003780 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003781 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3782 MGMT_STATUS_INVALID_PARAMS,
3783 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003784
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003785 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003786
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003787 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3788 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003789 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003790 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003791 goto done;
3792 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003793
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003794 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3795 sk);
3796 status = MGMT_STATUS_SUCCESS;
3797
3798done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003799 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3800 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003802 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003803
3804 return err;
3805}
3806
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003807static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3808 u16 len)
3809{
3810 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003811 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003812 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003813 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003814
3815 BT_DBG("%s", hdev->name);
3816
Szymon Jancc72d4b82012-03-16 16:02:57 +01003817 source = __le16_to_cpu(cp->source);
3818
3819 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003820 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3821 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003822
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003823 hci_dev_lock(hdev);
3824
Szymon Jancc72d4b82012-03-16 16:02:57 +01003825 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003826 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3827 hdev->devid_product = __le16_to_cpu(cp->product);
3828 hdev->devid_version = __le16_to_cpu(cp->version);
3829
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003830 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3831 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003832
Johan Hedberg890ea892013-03-15 17:06:52 -05003833 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003834 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003835 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003836
3837 hci_dev_unlock(hdev);
3838
3839 return err;
3840}
3841
Arman Uguray24b4f382015-03-23 15:57:12 -07003842static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3843 u16 opcode)
3844{
3845 BT_DBG("status %d", status);
3846}
3847
Marcel Holtmann1904a852015-01-11 13:50:44 -08003848static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3849 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003850{
3851 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003852 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003853 u8 instance;
3854 struct adv_info *adv_instance;
3855 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003856
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303857 hci_dev_lock(hdev);
3858
Johan Hedberg4375f102013-09-25 13:26:10 +03003859 if (status) {
3860 u8 mgmt_err = mgmt_status(status);
3861
3862 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3863 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303864 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003865 }
3866
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003867 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003868 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003869 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003870 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003871
Johan Hedberg4375f102013-09-25 13:26:10 +03003872 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3873 &match);
3874
3875 new_settings(hdev, match.sk);
3876
3877 if (match.sk)
3878 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303879
Arman Uguray24b4f382015-03-23 15:57:12 -07003880 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003881 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003882 */
3883 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003884 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003885 goto unlock;
3886
Florian Grandel7816b822015-06-18 03:16:45 +02003887 instance = hdev->cur_adv_instance;
3888 if (!instance) {
3889 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3890 struct adv_info, list);
3891 if (!adv_instance)
3892 goto unlock;
3893
3894 instance = adv_instance->instance;
3895 }
3896
Arman Uguray24b4f382015-03-23 15:57:12 -07003897 hci_req_init(&req, hdev);
3898
Johan Hedbergf2252572015-11-18 12:49:20 +02003899 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003900
Florian Grandel7816b822015-06-18 03:16:45 +02003901 if (!err)
3902 err = hci_req_run(&req, enable_advertising_instance);
3903
3904 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003905 BT_ERR("Failed to re-configure advertising");
3906
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303907unlock:
3908 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003909}
3910
Marcel Holtmann21b51872013-10-10 09:47:53 -07003911static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3912 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003913{
3914 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003915 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003916 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003917 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003918 int err;
3919
3920 BT_DBG("request for %s", hdev->name);
3921
Johan Hedberge6fe7982013-10-02 15:45:22 +03003922 status = mgmt_le_support(hdev);
3923 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003924 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3925 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003926
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003927 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003928 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3929 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003930
3931 hci_dev_lock(hdev);
3932
3933 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003934
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003935 /* The following conditions are ones which mean that we should
3936 * not do any HCI communication but directly send a mgmt
3937 * response to user space (after toggling the flag if
3938 * necessary).
3939 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003940 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003941 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3942 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003943 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003944 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003945 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003946 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003947
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003948 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003949 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07003950 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003951 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003952 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003953 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003954 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003955 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003956 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003957 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003958 }
3959
3960 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3961 if (err < 0)
3962 goto unlock;
3963
3964 if (changed)
3965 err = new_settings(hdev, sk);
3966
3967 goto unlock;
3968 }
3969
Johan Hedberg333ae952015-03-17 13:48:47 +02003970 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3971 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003972 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3973 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03003974 goto unlock;
3975 }
3976
3977 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3978 if (!cmd) {
3979 err = -ENOMEM;
3980 goto unlock;
3981 }
3982
3983 hci_req_init(&req, hdev);
3984
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003985 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003986 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003987 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003988 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003989
Florian Grandel7816b822015-06-18 03:16:45 +02003990 cancel_adv_timeout(hdev);
3991
Arman Uguray24b4f382015-03-23 15:57:12 -07003992 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02003993 /* Switch to instance "0" for the Set Advertising setting.
3994 * We cannot use update_[adv|scan_rsp]_data() here as the
3995 * HCI_ADVERTISING flag is not yet set.
3996 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02003997 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02003998 __hci_req_update_adv_data(&req, 0x00);
3999 __hci_req_update_scan_rsp_data(&req, 0x00);
4000 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004001 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02004002 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004003 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004004
4005 err = hci_req_run(&req, set_advertising_complete);
4006 if (err < 0)
4007 mgmt_pending_remove(cmd);
4008
4009unlock:
4010 hci_dev_unlock(hdev);
4011 return err;
4012}
4013
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004014static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4015 void *data, u16 len)
4016{
4017 struct mgmt_cp_set_static_address *cp = data;
4018 int err;
4019
4020 BT_DBG("%s", hdev->name);
4021
Marcel Holtmann62af4442013-10-02 22:10:32 -07004022 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004023 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4024 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004025
4026 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004027 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4028 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004029
4030 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4031 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004032 return mgmt_cmd_status(sk, hdev->id,
4033 MGMT_OP_SET_STATIC_ADDRESS,
4034 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004035
4036 /* Two most significant bits shall be set */
4037 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004038 return mgmt_cmd_status(sk, hdev->id,
4039 MGMT_OP_SET_STATIC_ADDRESS,
4040 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004041 }
4042
4043 hci_dev_lock(hdev);
4044
4045 bacpy(&hdev->static_addr, &cp->bdaddr);
4046
Marcel Holtmann93690c22015-03-06 10:11:21 -08004047 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4048 if (err < 0)
4049 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004050
Marcel Holtmann93690c22015-03-06 10:11:21 -08004051 err = new_settings(hdev, sk);
4052
4053unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004054 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004055 return err;
4056}
4057
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004058static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4059 void *data, u16 len)
4060{
4061 struct mgmt_cp_set_scan_params *cp = data;
4062 __u16 interval, window;
4063 int err;
4064
4065 BT_DBG("%s", hdev->name);
4066
4067 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004068 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4069 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004070
4071 interval = __le16_to_cpu(cp->interval);
4072
4073 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004074 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4075 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004076
4077 window = __le16_to_cpu(cp->window);
4078
4079 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004080 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4081 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004082
Marcel Holtmann899e1072013-10-14 09:55:32 -07004083 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004084 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4085 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004086
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004087 hci_dev_lock(hdev);
4088
4089 hdev->le_scan_interval = interval;
4090 hdev->le_scan_window = window;
4091
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004092 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4093 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004094
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004095 /* If background scan is running, restart it so new parameters are
4096 * loaded.
4097 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004098 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004099 hdev->discovery.state == DISCOVERY_STOPPED) {
4100 struct hci_request req;
4101
4102 hci_req_init(&req, hdev);
4103
4104 hci_req_add_le_scan_disable(&req);
4105 hci_req_add_le_passive_scan(&req);
4106
4107 hci_req_run(&req, NULL);
4108 }
4109
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004110 hci_dev_unlock(hdev);
4111
4112 return err;
4113}
4114
Marcel Holtmann1904a852015-01-11 13:50:44 -08004115static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4116 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004117{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004118 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004119
4120 BT_DBG("status 0x%02x", status);
4121
4122 hci_dev_lock(hdev);
4123
Johan Hedberg333ae952015-03-17 13:48:47 +02004124 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004125 if (!cmd)
4126 goto unlock;
4127
4128 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004129 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4130 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004131 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004132 struct mgmt_mode *cp = cmd->param;
4133
4134 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004135 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004136 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004137 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004138
Johan Hedberg33e38b32013-03-15 17:07:05 -05004139 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4140 new_settings(hdev, cmd->sk);
4141 }
4142
4143 mgmt_pending_remove(cmd);
4144
4145unlock:
4146 hci_dev_unlock(hdev);
4147}
4148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004149static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004150 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004151{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004152 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004153 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004154 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004155 int err;
4156
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004157 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004158
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004159 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004160 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004161 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4162 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004163
Johan Hedberga7e80f22013-01-09 16:05:19 +02004164 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004165 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4166 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004167
Antti Julkuf6422ec2011-06-22 13:11:56 +03004168 hci_dev_lock(hdev);
4169
Johan Hedberg333ae952015-03-17 13:48:47 +02004170 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004171 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4172 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004173 goto unlock;
4174 }
4175
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004176 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004177 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4178 hdev);
4179 goto unlock;
4180 }
4181
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004182 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004183 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004184 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4185 hdev);
4186 new_settings(hdev, sk);
4187 goto unlock;
4188 }
4189
Johan Hedberg33e38b32013-03-15 17:07:05 -05004190 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4191 data, len);
4192 if (!cmd) {
4193 err = -ENOMEM;
4194 goto unlock;
4195 }
4196
4197 hci_req_init(&req, hdev);
4198
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004199 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004200
4201 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004202 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004203 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4204 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004205 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004206 }
4207
Johan Hedberg33e38b32013-03-15 17:07:05 -05004208unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004209 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004210
Antti Julkuf6422ec2011-06-22 13:11:56 +03004211 return err;
4212}
4213
Marcel Holtmann1904a852015-01-11 13:50:44 -08004214static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004215{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004216 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004217
4218 BT_DBG("status 0x%02x", status);
4219
4220 hci_dev_lock(hdev);
4221
Johan Hedberg333ae952015-03-17 13:48:47 +02004222 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004223 if (!cmd)
4224 goto unlock;
4225
4226 if (status) {
4227 u8 mgmt_err = mgmt_status(status);
4228
4229 /* We need to restore the flag if related HCI commands
4230 * failed.
4231 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004232 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004233
Johan Hedberga69e8372015-03-06 21:08:53 +02004234 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004235 } else {
4236 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4237 new_settings(hdev, cmd->sk);
4238 }
4239
4240 mgmt_pending_remove(cmd);
4241
4242unlock:
4243 hci_dev_unlock(hdev);
4244}
4245
4246static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4247{
4248 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004249 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004250 struct hci_request req;
4251 int err;
4252
4253 BT_DBG("request for %s", hdev->name);
4254
4255 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004256 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4257 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004258
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004259 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004260 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4261 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004262
4263 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004264 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4265 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004266
4267 hci_dev_lock(hdev);
4268
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004269 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004270 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4271 goto unlock;
4272 }
4273
4274 if (!hdev_is_powered(hdev)) {
4275 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004276 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4277 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4278 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4279 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4280 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004281 }
4282
Marcel Holtmannce05d602015-03-13 02:11:03 -07004283 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004284
4285 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4286 if (err < 0)
4287 goto unlock;
4288
4289 err = new_settings(hdev, sk);
4290 goto unlock;
4291 }
4292
4293 /* Reject disabling when powered on */
4294 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004295 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4296 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004297 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004298 } else {
4299 /* When configuring a dual-mode controller to operate
4300 * with LE only and using a static address, then switching
4301 * BR/EDR back on is not allowed.
4302 *
4303 * Dual-mode controllers shall operate with the public
4304 * address as its identity address for BR/EDR and LE. So
4305 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004306 *
4307 * The same restrictions applies when secure connections
4308 * has been enabled. For BR/EDR this is a controller feature
4309 * while for LE it is a host stack feature. This means that
4310 * switching BR/EDR back on when secure connections has been
4311 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004312 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004313 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004314 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004315 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004316 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4317 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004318 goto unlock;
4319 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004320 }
4321
Johan Hedberg333ae952015-03-17 13:48:47 +02004322 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004323 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4324 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004325 goto unlock;
4326 }
4327
4328 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4329 if (!cmd) {
4330 err = -ENOMEM;
4331 goto unlock;
4332 }
4333
Johan Hedbergf2252572015-11-18 12:49:20 +02004334 /* We need to flip the bit already here so that
4335 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004336 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004337 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004338
4339 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004340
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004341 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004342 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004343
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004344 /* Since only the advertising data flags will change, there
4345 * is no need to update the scan response data.
4346 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004347 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004348
Johan Hedberg0663ca22013-10-02 13:43:14 +03004349 err = hci_req_run(&req, set_bredr_complete);
4350 if (err < 0)
4351 mgmt_pending_remove(cmd);
4352
4353unlock:
4354 hci_dev_unlock(hdev);
4355 return err;
4356}
4357
Johan Hedberga1443f52015-01-23 15:42:46 +02004358static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4359{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004360 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004361 struct mgmt_mode *cp;
4362
4363 BT_DBG("%s status %u", hdev->name, status);
4364
4365 hci_dev_lock(hdev);
4366
Johan Hedberg333ae952015-03-17 13:48:47 +02004367 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004368 if (!cmd)
4369 goto unlock;
4370
4371 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004372 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4373 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004374 goto remove;
4375 }
4376
4377 cp = cmd->param;
4378
4379 switch (cp->val) {
4380 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004381 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4382 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004383 break;
4384 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004385 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004386 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004387 break;
4388 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004389 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4390 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004391 break;
4392 }
4393
4394 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4395 new_settings(hdev, cmd->sk);
4396
4397remove:
4398 mgmt_pending_remove(cmd);
4399unlock:
4400 hci_dev_unlock(hdev);
4401}
4402
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004403static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4404 void *data, u16 len)
4405{
4406 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004407 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004408 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004409 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004410 int err;
4411
4412 BT_DBG("request for %s", hdev->name);
4413
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004414 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004415 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004416 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4417 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004418
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004419 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004420 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004421 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004422 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4423 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004424
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004425 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004426 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004427 MGMT_STATUS_INVALID_PARAMS);
4428
4429 hci_dev_lock(hdev);
4430
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004431 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004432 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004433 bool changed;
4434
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004435 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004436 changed = !hci_dev_test_and_set_flag(hdev,
4437 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004438 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004439 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004440 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004441 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004442 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004443 changed = hci_dev_test_and_clear_flag(hdev,
4444 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004445 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004446 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004447
4448 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4449 if (err < 0)
4450 goto failed;
4451
4452 if (changed)
4453 err = new_settings(hdev, sk);
4454
4455 goto failed;
4456 }
4457
Johan Hedberg333ae952015-03-17 13:48:47 +02004458 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004459 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4460 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004461 goto failed;
4462 }
4463
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004464 val = !!cp->val;
4465
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004466 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4467 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004468 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4469 goto failed;
4470 }
4471
4472 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4473 if (!cmd) {
4474 err = -ENOMEM;
4475 goto failed;
4476 }
4477
Johan Hedberga1443f52015-01-23 15:42:46 +02004478 hci_req_init(&req, hdev);
4479 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4480 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004481 if (err < 0) {
4482 mgmt_pending_remove(cmd);
4483 goto failed;
4484 }
4485
4486failed:
4487 hci_dev_unlock(hdev);
4488 return err;
4489}
4490
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004491static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4492 void *data, u16 len)
4493{
4494 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004495 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004496 int err;
4497
4498 BT_DBG("request for %s", hdev->name);
4499
Johan Hedbergb97109792014-06-24 14:00:28 +03004500 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004501 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4502 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004503
4504 hci_dev_lock(hdev);
4505
4506 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004507 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004508 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004509 changed = hci_dev_test_and_clear_flag(hdev,
4510 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004511
Johan Hedbergb97109792014-06-24 14:00:28 +03004512 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004513 use_changed = !hci_dev_test_and_set_flag(hdev,
4514 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004515 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004516 use_changed = hci_dev_test_and_clear_flag(hdev,
4517 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004518
4519 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004520 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004521 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4522 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4523 sizeof(mode), &mode);
4524 }
4525
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004526 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4527 if (err < 0)
4528 goto unlock;
4529
4530 if (changed)
4531 err = new_settings(hdev, sk);
4532
4533unlock:
4534 hci_dev_unlock(hdev);
4535 return err;
4536}
4537
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004538static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4539 u16 len)
4540{
4541 struct mgmt_cp_set_privacy *cp = cp_data;
4542 bool changed;
4543 int err;
4544
4545 BT_DBG("request for %s", hdev->name);
4546
4547 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004548 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4549 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004550
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004551 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004552 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4553 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004554
4555 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004556 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4557 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004558
4559 hci_dev_lock(hdev);
4560
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004561 /* If user space supports this command it is also expected to
4562 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4563 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004564 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004565
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004566 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004567 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004568 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004569 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004570 if (cp->privacy == 0x02)
4571 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4572 else
4573 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004574 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004575 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004576 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004577 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004578 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004579 }
4580
4581 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4582 if (err < 0)
4583 goto unlock;
4584
4585 if (changed)
4586 err = new_settings(hdev, sk);
4587
4588unlock:
4589 hci_dev_unlock(hdev);
4590 return err;
4591}
4592
Johan Hedberg41edf162014-02-18 10:19:35 +02004593static bool irk_is_valid(struct mgmt_irk_info *irk)
4594{
4595 switch (irk->addr.type) {
4596 case BDADDR_LE_PUBLIC:
4597 return true;
4598
4599 case BDADDR_LE_RANDOM:
4600 /* Two most significant bits shall be set */
4601 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4602 return false;
4603 return true;
4604 }
4605
4606 return false;
4607}
4608
4609static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4610 u16 len)
4611{
4612 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004613 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4614 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004615 u16 irk_count, expected_len;
4616 int i, err;
4617
4618 BT_DBG("request for %s", hdev->name);
4619
4620 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004621 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4622 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004623
4624 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004625 if (irk_count > max_irk_count) {
4626 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004627 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4628 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004629 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004630
4631 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4632 if (expected_len != len) {
4633 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004634 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004635 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4636 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004637 }
4638
4639 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4640
4641 for (i = 0; i < irk_count; i++) {
4642 struct mgmt_irk_info *key = &cp->irks[i];
4643
4644 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004645 return mgmt_cmd_status(sk, hdev->id,
4646 MGMT_OP_LOAD_IRKS,
4647 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004648 }
4649
4650 hci_dev_lock(hdev);
4651
4652 hci_smp_irks_clear(hdev);
4653
4654 for (i = 0; i < irk_count; i++) {
4655 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004656
Johan Hedberg85813a72015-10-21 18:02:59 +03004657 hci_add_irk(hdev, &irk->addr.bdaddr,
4658 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004659 BDADDR_ANY);
4660 }
4661
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004662 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004663
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004664 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004665
4666 hci_dev_unlock(hdev);
4667
4668 return err;
4669}
4670
Johan Hedberg3f706b72013-01-20 14:27:16 +02004671static bool ltk_is_valid(struct mgmt_ltk_info *key)
4672{
4673 if (key->master != 0x00 && key->master != 0x01)
4674 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004675
4676 switch (key->addr.type) {
4677 case BDADDR_LE_PUBLIC:
4678 return true;
4679
4680 case BDADDR_LE_RANDOM:
4681 /* Two most significant bits shall be set */
4682 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4683 return false;
4684 return true;
4685 }
4686
4687 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004688}
4689
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004690static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004691 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004692{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004693 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004694 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4695 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004696 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004697 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004698
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004699 BT_DBG("request for %s", hdev->name);
4700
4701 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004702 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4703 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004704
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004705 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004706 if (key_count > max_key_count) {
4707 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004708 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4709 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004710 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004711
4712 expected_len = sizeof(*cp) + key_count *
4713 sizeof(struct mgmt_ltk_info);
4714 if (expected_len != len) {
4715 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004716 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004717 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4718 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004719 }
4720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004721 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004722
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004723 for (i = 0; i < key_count; i++) {
4724 struct mgmt_ltk_info *key = &cp->keys[i];
4725
Johan Hedberg3f706b72013-01-20 14:27:16 +02004726 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004727 return mgmt_cmd_status(sk, hdev->id,
4728 MGMT_OP_LOAD_LONG_TERM_KEYS,
4729 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004730 }
4731
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004732 hci_dev_lock(hdev);
4733
4734 hci_smp_ltks_clear(hdev);
4735
4736 for (i = 0; i < key_count; i++) {
4737 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004738 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004739
Johan Hedberg61b43352014-05-29 19:36:53 +03004740 switch (key->type) {
4741 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004742 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004743 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004744 break;
4745 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004746 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004747 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004748 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004749 case MGMT_LTK_P256_UNAUTH:
4750 authenticated = 0x00;
4751 type = SMP_LTK_P256;
4752 break;
4753 case MGMT_LTK_P256_AUTH:
4754 authenticated = 0x01;
4755 type = SMP_LTK_P256;
4756 break;
4757 case MGMT_LTK_P256_DEBUG:
4758 authenticated = 0x00;
4759 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004760 default:
4761 continue;
4762 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004763
Johan Hedberg85813a72015-10-21 18:02:59 +03004764 hci_add_ltk(hdev, &key->addr.bdaddr,
4765 le_addr_type(key->addr.type), type, authenticated,
4766 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004767 }
4768
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004769 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004770 NULL, 0);
4771
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004772 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004773
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004774 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004775}
4776
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004777static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004778{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004779 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004780 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004781 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004782
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004783 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004784
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004785 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004786 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004787 rp.tx_power = conn->tx_power;
4788 rp.max_tx_power = conn->max_tx_power;
4789 } else {
4790 rp.rssi = HCI_RSSI_INVALID;
4791 rp.tx_power = HCI_TX_POWER_INVALID;
4792 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004793 }
4794
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004795 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4796 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004797
4798 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004799 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004800
4801 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004802}
4803
Marcel Holtmann1904a852015-01-11 13:50:44 -08004804static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4805 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004806{
4807 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004808 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004809 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004810 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004811 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004812
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004813 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004814
4815 hci_dev_lock(hdev);
4816
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004817 /* Commands sent in request are either Read RSSI or Read Transmit Power
4818 * Level so we check which one was last sent to retrieve connection
4819 * handle. Both commands have handle as first parameter so it's safe to
4820 * cast data on the same command struct.
4821 *
4822 * First command sent is always Read RSSI and we fail only if it fails.
4823 * In other case we simply override error to indicate success as we
4824 * already remembered if TX power value is actually valid.
4825 */
4826 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4827 if (!cp) {
4828 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004829 status = MGMT_STATUS_SUCCESS;
4830 } else {
4831 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004832 }
4833
4834 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004835 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004836 goto unlock;
4837 }
4838
4839 handle = __le16_to_cpu(cp->handle);
4840 conn = hci_conn_hash_lookup_handle(hdev, handle);
4841 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004842 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004843 goto unlock;
4844 }
4845
Johan Hedberg333ae952015-03-17 13:48:47 +02004846 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004847 if (!cmd)
4848 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004849
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004850 cmd->cmd_complete(cmd, status);
4851 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004852
4853unlock:
4854 hci_dev_unlock(hdev);
4855}
4856
4857static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4858 u16 len)
4859{
4860 struct mgmt_cp_get_conn_info *cp = data;
4861 struct mgmt_rp_get_conn_info rp;
4862 struct hci_conn *conn;
4863 unsigned long conn_info_age;
4864 int err = 0;
4865
4866 BT_DBG("%s", hdev->name);
4867
4868 memset(&rp, 0, sizeof(rp));
4869 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4870 rp.addr.type = cp->addr.type;
4871
4872 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004873 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4874 MGMT_STATUS_INVALID_PARAMS,
4875 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004876
4877 hci_dev_lock(hdev);
4878
4879 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004880 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4881 MGMT_STATUS_NOT_POWERED, &rp,
4882 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004883 goto unlock;
4884 }
4885
4886 if (cp->addr.type == BDADDR_BREDR)
4887 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4888 &cp->addr.bdaddr);
4889 else
4890 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4891
4892 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004893 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4894 MGMT_STATUS_NOT_CONNECTED, &rp,
4895 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004896 goto unlock;
4897 }
4898
Johan Hedberg333ae952015-03-17 13:48:47 +02004899 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004900 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4901 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004902 goto unlock;
4903 }
4904
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004905 /* To avoid client trying to guess when to poll again for information we
4906 * calculate conn info age as random value between min/max set in hdev.
4907 */
4908 conn_info_age = hdev->conn_info_min_age +
4909 prandom_u32_max(hdev->conn_info_max_age -
4910 hdev->conn_info_min_age);
4911
4912 /* Query controller to refresh cached values if they are too old or were
4913 * never read.
4914 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004915 if (time_after(jiffies, conn->conn_info_timestamp +
4916 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004917 !conn->conn_info_timestamp) {
4918 struct hci_request req;
4919 struct hci_cp_read_tx_power req_txp_cp;
4920 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004921 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004922
4923 hci_req_init(&req, hdev);
4924 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4925 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4926 &req_rssi_cp);
4927
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004928 /* For LE links TX power does not change thus we don't need to
4929 * query for it once value is known.
4930 */
4931 if (!bdaddr_type_is_le(cp->addr.type) ||
4932 conn->tx_power == HCI_TX_POWER_INVALID) {
4933 req_txp_cp.handle = cpu_to_le16(conn->handle);
4934 req_txp_cp.type = 0x00;
4935 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4936 sizeof(req_txp_cp), &req_txp_cp);
4937 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004938
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004939 /* Max TX power needs to be read only once per connection */
4940 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4941 req_txp_cp.handle = cpu_to_le16(conn->handle);
4942 req_txp_cp.type = 0x01;
4943 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4944 sizeof(req_txp_cp), &req_txp_cp);
4945 }
4946
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004947 err = hci_req_run(&req, conn_info_refresh_complete);
4948 if (err < 0)
4949 goto unlock;
4950
4951 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4952 data, len);
4953 if (!cmd) {
4954 err = -ENOMEM;
4955 goto unlock;
4956 }
4957
4958 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004959 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004960 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004961
4962 conn->conn_info_timestamp = jiffies;
4963 } else {
4964 /* Cache is valid, just reply with values cached in hci_conn */
4965 rp.rssi = conn->rssi;
4966 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004967 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004968
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004969 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4970 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004971 }
4972
4973unlock:
4974 hci_dev_unlock(hdev);
4975 return err;
4976}
4977
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004978static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004979{
4980 struct hci_conn *conn = cmd->user_data;
4981 struct mgmt_rp_get_clock_info rp;
4982 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004983 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004984
4985 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02004986 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02004987
4988 if (status)
4989 goto complete;
4990
4991 hdev = hci_dev_get(cmd->index);
4992 if (hdev) {
4993 rp.local_clock = cpu_to_le32(hdev->clock);
4994 hci_dev_put(hdev);
4995 }
4996
4997 if (conn) {
4998 rp.piconet_clock = cpu_to_le32(conn->clock);
4999 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5000 }
5001
5002complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005003 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5004 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005005
5006 if (conn) {
5007 hci_conn_drop(conn);
5008 hci_conn_put(conn);
5009 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005010
5011 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005012}
5013
Marcel Holtmann1904a852015-01-11 13:50:44 -08005014static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005015{
Johan Hedberg95868422014-06-28 17:54:07 +03005016 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005017 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005018 struct hci_conn *conn;
5019
5020 BT_DBG("%s status %u", hdev->name, status);
5021
5022 hci_dev_lock(hdev);
5023
5024 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5025 if (!hci_cp)
5026 goto unlock;
5027
5028 if (hci_cp->which) {
5029 u16 handle = __le16_to_cpu(hci_cp->handle);
5030 conn = hci_conn_hash_lookup_handle(hdev, handle);
5031 } else {
5032 conn = NULL;
5033 }
5034
Johan Hedberg333ae952015-03-17 13:48:47 +02005035 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005036 if (!cmd)
5037 goto unlock;
5038
Johan Hedberg69487372014-12-05 13:36:07 +02005039 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005040 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005041
5042unlock:
5043 hci_dev_unlock(hdev);
5044}
5045
5046static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5047 u16 len)
5048{
5049 struct mgmt_cp_get_clock_info *cp = data;
5050 struct mgmt_rp_get_clock_info rp;
5051 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005052 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005053 struct hci_request req;
5054 struct hci_conn *conn;
5055 int err;
5056
5057 BT_DBG("%s", hdev->name);
5058
5059 memset(&rp, 0, sizeof(rp));
5060 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5061 rp.addr.type = cp->addr.type;
5062
5063 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005064 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5065 MGMT_STATUS_INVALID_PARAMS,
5066 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005067
5068 hci_dev_lock(hdev);
5069
5070 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005071 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5072 MGMT_STATUS_NOT_POWERED, &rp,
5073 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005074 goto unlock;
5075 }
5076
5077 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5078 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5079 &cp->addr.bdaddr);
5080 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005081 err = mgmt_cmd_complete(sk, hdev->id,
5082 MGMT_OP_GET_CLOCK_INFO,
5083 MGMT_STATUS_NOT_CONNECTED,
5084 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005085 goto unlock;
5086 }
5087 } else {
5088 conn = NULL;
5089 }
5090
5091 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5092 if (!cmd) {
5093 err = -ENOMEM;
5094 goto unlock;
5095 }
5096
Johan Hedberg69487372014-12-05 13:36:07 +02005097 cmd->cmd_complete = clock_info_cmd_complete;
5098
Johan Hedberg95868422014-06-28 17:54:07 +03005099 hci_req_init(&req, hdev);
5100
5101 memset(&hci_cp, 0, sizeof(hci_cp));
5102 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5103
5104 if (conn) {
5105 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005106 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005107
5108 hci_cp.handle = cpu_to_le16(conn->handle);
5109 hci_cp.which = 0x01; /* Piconet clock */
5110 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5111 }
5112
5113 err = hci_req_run(&req, get_clock_info_complete);
5114 if (err < 0)
5115 mgmt_pending_remove(cmd);
5116
5117unlock:
5118 hci_dev_unlock(hdev);
5119 return err;
5120}
5121
Johan Hedberg5a154e62014-12-19 22:26:02 +02005122static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5123{
5124 struct hci_conn *conn;
5125
5126 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5127 if (!conn)
5128 return false;
5129
5130 if (conn->dst_type != type)
5131 return false;
5132
5133 if (conn->state != BT_CONNECTED)
5134 return false;
5135
5136 return true;
5137}
5138
5139/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005140static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005141 u8 addr_type, u8 auto_connect)
5142{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005143 struct hci_conn_params *params;
5144
5145 params = hci_conn_params_add(hdev, addr, addr_type);
5146 if (!params)
5147 return -EIO;
5148
5149 if (params->auto_connect == auto_connect)
5150 return 0;
5151
5152 list_del_init(&params->action);
5153
5154 switch (auto_connect) {
5155 case HCI_AUTO_CONN_DISABLED:
5156 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005157 /* If auto connect is being disabled when we're trying to
5158 * connect to device, keep connecting.
5159 */
5160 if (params->explicit_connect)
5161 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005162 break;
5163 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005164 if (params->explicit_connect)
5165 list_add(&params->action, &hdev->pend_le_conns);
5166 else
5167 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005168 break;
5169 case HCI_AUTO_CONN_DIRECT:
5170 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005171 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005172 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005173 break;
5174 }
5175
5176 params->auto_connect = auto_connect;
5177
5178 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5179 auto_connect);
5180
5181 return 0;
5182}
5183
Marcel Holtmann8afef092014-06-29 22:28:34 +02005184static void device_added(struct sock *sk, struct hci_dev *hdev,
5185 bdaddr_t *bdaddr, u8 type, u8 action)
5186{
5187 struct mgmt_ev_device_added ev;
5188
5189 bacpy(&ev.addr.bdaddr, bdaddr);
5190 ev.addr.type = type;
5191 ev.action = action;
5192
5193 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5194}
5195
Marcel Holtmann2faade52014-06-29 19:44:03 +02005196static int add_device(struct sock *sk, struct hci_dev *hdev,
5197 void *data, u16 len)
5198{
5199 struct mgmt_cp_add_device *cp = data;
5200 u8 auto_conn, addr_type;
5201 int err;
5202
5203 BT_DBG("%s", hdev->name);
5204
Johan Hedberg66593582014-07-09 12:59:14 +03005205 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005206 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005207 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5208 MGMT_STATUS_INVALID_PARAMS,
5209 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005210
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005211 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005212 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5213 MGMT_STATUS_INVALID_PARAMS,
5214 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005215
5216 hci_dev_lock(hdev);
5217
Johan Hedberg66593582014-07-09 12:59:14 +03005218 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005219 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005220 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005221 err = mgmt_cmd_complete(sk, hdev->id,
5222 MGMT_OP_ADD_DEVICE,
5223 MGMT_STATUS_INVALID_PARAMS,
5224 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005225 goto unlock;
5226 }
5227
5228 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5229 cp->addr.type);
5230 if (err)
5231 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005232
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005233 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005234
Johan Hedberg66593582014-07-09 12:59:14 +03005235 goto added;
5236 }
5237
Johan Hedberg85813a72015-10-21 18:02:59 +03005238 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005239
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005240 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005241 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005242 else if (cp->action == 0x01)
5243 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005244 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005245 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005246
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005247 /* Kernel internally uses conn_params with resolvable private
5248 * address, but Add Device allows only identity addresses.
5249 * Make sure it is enforced before calling
5250 * hci_conn_params_lookup.
5251 */
5252 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005253 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5254 MGMT_STATUS_INVALID_PARAMS,
5255 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005256 goto unlock;
5257 }
5258
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005259 /* If the connection parameters don't exist for this device,
5260 * they will be created and configured with defaults.
5261 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005262 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005263 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005264 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5265 MGMT_STATUS_FAILED, &cp->addr,
5266 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005267 goto unlock;
5268 }
5269
Johan Hedberg51d7a942015-11-11 08:11:18 +02005270 hci_update_background_scan(hdev);
5271
Johan Hedberg66593582014-07-09 12:59:14 +03005272added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005273 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5274
Johan Hedberg51d7a942015-11-11 08:11:18 +02005275 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5276 MGMT_STATUS_SUCCESS, &cp->addr,
5277 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005278
5279unlock:
5280 hci_dev_unlock(hdev);
5281 return err;
5282}
5283
Marcel Holtmann8afef092014-06-29 22:28:34 +02005284static void device_removed(struct sock *sk, struct hci_dev *hdev,
5285 bdaddr_t *bdaddr, u8 type)
5286{
5287 struct mgmt_ev_device_removed ev;
5288
5289 bacpy(&ev.addr.bdaddr, bdaddr);
5290 ev.addr.type = type;
5291
5292 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5293}
5294
Marcel Holtmann2faade52014-06-29 19:44:03 +02005295static int remove_device(struct sock *sk, struct hci_dev *hdev,
5296 void *data, u16 len)
5297{
5298 struct mgmt_cp_remove_device *cp = data;
5299 int err;
5300
5301 BT_DBG("%s", hdev->name);
5302
5303 hci_dev_lock(hdev);
5304
5305 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005306 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005307 u8 addr_type;
5308
Johan Hedberg66593582014-07-09 12:59:14 +03005309 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005310 err = mgmt_cmd_complete(sk, hdev->id,
5311 MGMT_OP_REMOVE_DEVICE,
5312 MGMT_STATUS_INVALID_PARAMS,
5313 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005314 goto unlock;
5315 }
5316
Johan Hedberg66593582014-07-09 12:59:14 +03005317 if (cp->addr.type == BDADDR_BREDR) {
5318 err = hci_bdaddr_list_del(&hdev->whitelist,
5319 &cp->addr.bdaddr,
5320 cp->addr.type);
5321 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005322 err = mgmt_cmd_complete(sk, hdev->id,
5323 MGMT_OP_REMOVE_DEVICE,
5324 MGMT_STATUS_INVALID_PARAMS,
5325 &cp->addr,
5326 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005327 goto unlock;
5328 }
5329
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005330 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005331
Johan Hedberg66593582014-07-09 12:59:14 +03005332 device_removed(sk, hdev, &cp->addr.bdaddr,
5333 cp->addr.type);
5334 goto complete;
5335 }
5336
Johan Hedberg85813a72015-10-21 18:02:59 +03005337 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005338
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005339 /* Kernel internally uses conn_params with resolvable private
5340 * address, but Remove Device allows only identity addresses.
5341 * Make sure it is enforced before calling
5342 * hci_conn_params_lookup.
5343 */
5344 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005345 err = mgmt_cmd_complete(sk, hdev->id,
5346 MGMT_OP_REMOVE_DEVICE,
5347 MGMT_STATUS_INVALID_PARAMS,
5348 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005349 goto unlock;
5350 }
5351
Johan Hedbergc71593d2014-07-02 17:37:28 +03005352 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5353 addr_type);
5354 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005355 err = mgmt_cmd_complete(sk, hdev->id,
5356 MGMT_OP_REMOVE_DEVICE,
5357 MGMT_STATUS_INVALID_PARAMS,
5358 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005359 goto unlock;
5360 }
5361
Johan Hedberg679d2b62015-10-16 10:07:52 +03005362 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5363 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005364 err = mgmt_cmd_complete(sk, hdev->id,
5365 MGMT_OP_REMOVE_DEVICE,
5366 MGMT_STATUS_INVALID_PARAMS,
5367 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005368 goto unlock;
5369 }
5370
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005371 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005372 list_del(&params->list);
5373 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005374 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005375
5376 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005377 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005378 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005379 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005380
Marcel Holtmann2faade52014-06-29 19:44:03 +02005381 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005382 err = mgmt_cmd_complete(sk, hdev->id,
5383 MGMT_OP_REMOVE_DEVICE,
5384 MGMT_STATUS_INVALID_PARAMS,
5385 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005386 goto unlock;
5387 }
5388
Johan Hedberg66593582014-07-09 12:59:14 +03005389 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5390 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5391 list_del(&b->list);
5392 kfree(b);
5393 }
5394
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005395 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005396
Johan Hedberg19de0822014-07-06 13:06:51 +03005397 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5398 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5399 continue;
5400 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005401 if (p->explicit_connect) {
5402 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5403 continue;
5404 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005405 list_del(&p->action);
5406 list_del(&p->list);
5407 kfree(p);
5408 }
5409
5410 BT_DBG("All LE connection parameters were removed");
5411
Johan Hedberg51d7a942015-11-11 08:11:18 +02005412 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005413 }
5414
Johan Hedberg66593582014-07-09 12:59:14 +03005415complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005416 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5417 MGMT_STATUS_SUCCESS, &cp->addr,
5418 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005419unlock:
5420 hci_dev_unlock(hdev);
5421 return err;
5422}
5423
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005424static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5425 u16 len)
5426{
5427 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005428 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5429 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005430 u16 param_count, expected_len;
5431 int i;
5432
5433 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005434 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5435 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005436
5437 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005438 if (param_count > max_param_count) {
5439 BT_ERR("load_conn_param: too big param_count value %u",
5440 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005441 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5442 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005443 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005444
5445 expected_len = sizeof(*cp) + param_count *
5446 sizeof(struct mgmt_conn_param);
5447 if (expected_len != len) {
5448 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5449 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005450 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5451 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005452 }
5453
5454 BT_DBG("%s param_count %u", hdev->name, param_count);
5455
5456 hci_dev_lock(hdev);
5457
5458 hci_conn_params_clear_disabled(hdev);
5459
5460 for (i = 0; i < param_count; i++) {
5461 struct mgmt_conn_param *param = &cp->params[i];
5462 struct hci_conn_params *hci_param;
5463 u16 min, max, latency, timeout;
5464 u8 addr_type;
5465
5466 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5467 param->addr.type);
5468
5469 if (param->addr.type == BDADDR_LE_PUBLIC) {
5470 addr_type = ADDR_LE_DEV_PUBLIC;
5471 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5472 addr_type = ADDR_LE_DEV_RANDOM;
5473 } else {
5474 BT_ERR("Ignoring invalid connection parameters");
5475 continue;
5476 }
5477
5478 min = le16_to_cpu(param->min_interval);
5479 max = le16_to_cpu(param->max_interval);
5480 latency = le16_to_cpu(param->latency);
5481 timeout = le16_to_cpu(param->timeout);
5482
5483 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5484 min, max, latency, timeout);
5485
5486 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5487 BT_ERR("Ignoring invalid connection parameters");
5488 continue;
5489 }
5490
5491 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5492 addr_type);
5493 if (!hci_param) {
5494 BT_ERR("Failed to add connection parameters");
5495 continue;
5496 }
5497
5498 hci_param->conn_min_interval = min;
5499 hci_param->conn_max_interval = max;
5500 hci_param->conn_latency = latency;
5501 hci_param->supervision_timeout = timeout;
5502 }
5503
5504 hci_dev_unlock(hdev);
5505
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005506 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5507 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005508}
5509
Marcel Holtmanndbece372014-07-04 18:11:55 +02005510static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5511 void *data, u16 len)
5512{
5513 struct mgmt_cp_set_external_config *cp = data;
5514 bool changed;
5515 int err;
5516
5517 BT_DBG("%s", hdev->name);
5518
5519 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005520 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5521 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005522
5523 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005524 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5525 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005526
5527 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005528 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5529 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005530
5531 hci_dev_lock(hdev);
5532
5533 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005534 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005535 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005536 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005537
5538 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5539 if (err < 0)
5540 goto unlock;
5541
5542 if (!changed)
5543 goto unlock;
5544
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005545 err = new_options(hdev, sk);
5546
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005547 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005548 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005549
Marcel Holtmann516018a2015-03-13 02:11:04 -07005550 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005551 hci_dev_set_flag(hdev, HCI_CONFIG);
5552 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005553
5554 queue_work(hdev->req_workqueue, &hdev->power_on);
5555 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005556 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005557 mgmt_index_added(hdev);
5558 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005559 }
5560
5561unlock:
5562 hci_dev_unlock(hdev);
5563 return err;
5564}
5565
Marcel Holtmann9713c172014-07-06 12:11:15 +02005566static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5567 void *data, u16 len)
5568{
5569 struct mgmt_cp_set_public_address *cp = data;
5570 bool changed;
5571 int err;
5572
5573 BT_DBG("%s", hdev->name);
5574
5575 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005576 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5577 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005578
5579 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005580 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5581 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005582
5583 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005584 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5585 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005586
5587 hci_dev_lock(hdev);
5588
5589 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5590 bacpy(&hdev->public_addr, &cp->bdaddr);
5591
5592 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5593 if (err < 0)
5594 goto unlock;
5595
5596 if (!changed)
5597 goto unlock;
5598
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005599 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005600 err = new_options(hdev, sk);
5601
5602 if (is_configured(hdev)) {
5603 mgmt_index_removed(hdev);
5604
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005605 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005606
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005607 hci_dev_set_flag(hdev, HCI_CONFIG);
5608 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005609
5610 queue_work(hdev->req_workqueue, &hdev->power_on);
5611 }
5612
5613unlock:
5614 hci_dev_unlock(hdev);
5615 return err;
5616}
5617
Johan Hedberg40f66c02015-04-07 21:52:22 +03005618static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5619 u16 opcode, struct sk_buff *skb)
5620{
5621 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5622 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5623 u8 *h192, *r192, *h256, *r256;
5624 struct mgmt_pending_cmd *cmd;
5625 u16 eir_len;
5626 int err;
5627
5628 BT_DBG("%s status %u", hdev->name, status);
5629
5630 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5631 if (!cmd)
5632 return;
5633
5634 mgmt_cp = cmd->param;
5635
5636 if (status) {
5637 status = mgmt_status(status);
5638 eir_len = 0;
5639
5640 h192 = NULL;
5641 r192 = NULL;
5642 h256 = NULL;
5643 r256 = NULL;
5644 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5645 struct hci_rp_read_local_oob_data *rp;
5646
5647 if (skb->len != sizeof(*rp)) {
5648 status = MGMT_STATUS_FAILED;
5649 eir_len = 0;
5650 } else {
5651 status = MGMT_STATUS_SUCCESS;
5652 rp = (void *)skb->data;
5653
5654 eir_len = 5 + 18 + 18;
5655 h192 = rp->hash;
5656 r192 = rp->rand;
5657 h256 = NULL;
5658 r256 = NULL;
5659 }
5660 } else {
5661 struct hci_rp_read_local_oob_ext_data *rp;
5662
5663 if (skb->len != sizeof(*rp)) {
5664 status = MGMT_STATUS_FAILED;
5665 eir_len = 0;
5666 } else {
5667 status = MGMT_STATUS_SUCCESS;
5668 rp = (void *)skb->data;
5669
5670 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5671 eir_len = 5 + 18 + 18;
5672 h192 = NULL;
5673 r192 = NULL;
5674 } else {
5675 eir_len = 5 + 18 + 18 + 18 + 18;
5676 h192 = rp->hash192;
5677 r192 = rp->rand192;
5678 }
5679
5680 h256 = rp->hash256;
5681 r256 = rp->rand256;
5682 }
5683 }
5684
5685 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5686 if (!mgmt_rp)
5687 goto done;
5688
5689 if (status)
5690 goto send_rsp;
5691
5692 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5693 hdev->dev_class, 3);
5694
5695 if (h192 && r192) {
5696 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5697 EIR_SSP_HASH_C192, h192, 16);
5698 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5699 EIR_SSP_RAND_R192, r192, 16);
5700 }
5701
5702 if (h256 && r256) {
5703 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5704 EIR_SSP_HASH_C256, h256, 16);
5705 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5706 EIR_SSP_RAND_R256, r256, 16);
5707 }
5708
5709send_rsp:
5710 mgmt_rp->type = mgmt_cp->type;
5711 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5712
5713 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5714 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5715 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5716 if (err < 0 || status)
5717 goto done;
5718
5719 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5720
5721 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5722 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5723 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5724done:
5725 kfree(mgmt_rp);
5726 mgmt_pending_remove(cmd);
5727}
5728
5729static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5730 struct mgmt_cp_read_local_oob_ext_data *cp)
5731{
5732 struct mgmt_pending_cmd *cmd;
5733 struct hci_request req;
5734 int err;
5735
5736 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5737 cp, sizeof(*cp));
5738 if (!cmd)
5739 return -ENOMEM;
5740
5741 hci_req_init(&req, hdev);
5742
5743 if (bredr_sc_enabled(hdev))
5744 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5745 else
5746 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5747
5748 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5749 if (err < 0) {
5750 mgmt_pending_remove(cmd);
5751 return err;
5752 }
5753
5754 return 0;
5755}
5756
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005757static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5758 void *data, u16 data_len)
5759{
5760 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5761 struct mgmt_rp_read_local_oob_ext_data *rp;
5762 size_t rp_len;
5763 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005764 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005765 int err;
5766
5767 BT_DBG("%s", hdev->name);
5768
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005769 if (hdev_is_powered(hdev)) {
5770 switch (cp->type) {
5771 case BIT(BDADDR_BREDR):
5772 status = mgmt_bredr_support(hdev);
5773 if (status)
5774 eir_len = 0;
5775 else
5776 eir_len = 5;
5777 break;
5778 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5779 status = mgmt_le_support(hdev);
5780 if (status)
5781 eir_len = 0;
5782 else
5783 eir_len = 9 + 3 + 18 + 18 + 3;
5784 break;
5785 default:
5786 status = MGMT_STATUS_INVALID_PARAMS;
5787 eir_len = 0;
5788 break;
5789 }
5790 } else {
5791 status = MGMT_STATUS_NOT_POWERED;
5792 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005793 }
5794
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005795 rp_len = sizeof(*rp) + eir_len;
5796 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005797 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005798 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005799
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005800 if (status)
5801 goto complete;
5802
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005803 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005804
5805 eir_len = 0;
5806 switch (cp->type) {
5807 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005808 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5809 err = read_local_ssp_oob_req(hdev, sk, cp);
5810 hci_dev_unlock(hdev);
5811 if (!err)
5812 goto done;
5813
5814 status = MGMT_STATUS_FAILED;
5815 goto complete;
5816 } else {
5817 eir_len = eir_append_data(rp->eir, eir_len,
5818 EIR_CLASS_OF_DEV,
5819 hdev->dev_class, 3);
5820 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005821 break;
5822 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005823 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5824 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005825 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005826 status = MGMT_STATUS_FAILED;
5827 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005828 }
5829
Marcel Holtmanne2135682015-04-02 12:00:58 -07005830 /* This should return the active RPA, but since the RPA
5831 * is only programmed on demand, it is really hard to fill
5832 * this in at the moment. For now disallow retrieving
5833 * local out-of-band data when privacy is in use.
5834 *
5835 * Returning the identity address will not help here since
5836 * pairing happens before the identity resolving key is
5837 * known and thus the connection establishment happens
5838 * based on the RPA and not the identity address.
5839 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005840 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005841 hci_dev_unlock(hdev);
5842 status = MGMT_STATUS_REJECTED;
5843 goto complete;
5844 }
5845
5846 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5847 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5848 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5849 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005850 memcpy(addr, &hdev->static_addr, 6);
5851 addr[6] = 0x01;
5852 } else {
5853 memcpy(addr, &hdev->bdaddr, 6);
5854 addr[6] = 0x00;
5855 }
5856
5857 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5858 addr, sizeof(addr));
5859
5860 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5861 role = 0x02;
5862 else
5863 role = 0x01;
5864
5865 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5866 &role, sizeof(role));
5867
Marcel Holtmann5082a592015-03-16 12:39:00 -07005868 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5869 eir_len = eir_append_data(rp->eir, eir_len,
5870 EIR_LE_SC_CONFIRM,
5871 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005872
Marcel Holtmann5082a592015-03-16 12:39:00 -07005873 eir_len = eir_append_data(rp->eir, eir_len,
5874 EIR_LE_SC_RANDOM,
5875 rand, sizeof(rand));
5876 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005877
Johan Hedbergf2252572015-11-18 12:49:20 +02005878 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005879
5880 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5881 flags |= LE_AD_NO_BREDR;
5882
5883 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5884 &flags, sizeof(flags));
5885 break;
5886 }
5887
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005888 hci_dev_unlock(hdev);
5889
Marcel Holtmann72000df2015-03-16 16:11:21 -07005890 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5891
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005892 status = MGMT_STATUS_SUCCESS;
5893
5894complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005895 rp->type = cp->type;
5896 rp->eir_len = cpu_to_le16(eir_len);
5897
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005898 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005899 status, rp, sizeof(*rp) + eir_len);
5900 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005901 goto done;
5902
5903 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5904 rp, sizeof(*rp) + eir_len,
5905 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005906
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005907done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005908 kfree(rp);
5909
5910 return err;
5911}
5912
Arman Uguray089fa8c2015-03-25 18:53:45 -07005913static u32 get_supported_adv_flags(struct hci_dev *hdev)
5914{
5915 u32 flags = 0;
5916
5917 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5918 flags |= MGMT_ADV_FLAG_DISCOV;
5919 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5920 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
Michał Narajowski7c295c42016-09-18 12:50:02 +02005921 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005922
5923 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5924 flags |= MGMT_ADV_FLAG_TX_POWER;
5925
5926 return flags;
5927}
5928
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005929static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5930 void *data, u16 data_len)
5931{
5932 struct mgmt_rp_read_adv_features *rp;
5933 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005934 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005935 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005936 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005937 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005938
5939 BT_DBG("%s", hdev->name);
5940
Arman Uguray089fa8c2015-03-25 18:53:45 -07005941 if (!lmp_le_capable(hdev))
5942 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5943 MGMT_STATUS_REJECTED);
5944
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005945 hci_dev_lock(hdev);
5946
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005947 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005948 rp = kmalloc(rp_len, GFP_ATOMIC);
5949 if (!rp) {
5950 hci_dev_unlock(hdev);
5951 return -ENOMEM;
5952 }
5953
Arman Uguray089fa8c2015-03-25 18:53:45 -07005954 supported_flags = get_supported_adv_flags(hdev);
5955
5956 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005957 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5958 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005959 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005960 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005961
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005962 instance = rp->instance;
5963 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5964 *instance = adv_instance->instance;
5965 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005966 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005967
5968 hci_dev_unlock(hdev);
5969
5970 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5971 MGMT_STATUS_SUCCESS, rp, rp_len);
5972
5973 kfree(rp);
5974
5975 return err;
5976}
5977
Arman Uguray4117ed72015-03-23 15:57:14 -07005978static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005979 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005980{
Arman Uguray4117ed72015-03-23 15:57:14 -07005981 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005982 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005983 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005984 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005985
Marcel Holtmann31a32482015-11-19 16:16:42 +01005986 if (is_adv_data) {
5987 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5988 MGMT_ADV_FLAG_LIMITED_DISCOV |
5989 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5990 flags_managed = true;
5991 max_len -= 3;
5992 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005993
Marcel Holtmann31a32482015-11-19 16:16:42 +01005994 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5995 tx_power_managed = true;
5996 max_len -= 3;
5997 }
Michał Narajowski7c295c42016-09-18 12:50:02 +02005998 } else {
5999 /* at least 1 byte of name should fit in */
6000 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
6001 max_len -= 3;
Arman Uguray5507e352015-03-25 18:53:44 -07006002 }
6003
Arman Uguray4117ed72015-03-23 15:57:14 -07006004 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006005 return false;
6006
Arman Uguray4117ed72015-03-23 15:57:14 -07006007 /* Make sure that the data is correctly formatted. */
6008 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6009 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07006010
Arman Ugurayb44133f2015-03-25 18:53:41 -07006011 if (flags_managed && data[i + 1] == EIR_FLAGS)
6012 return false;
6013
Arman Uguray5507e352015-03-25 18:53:44 -07006014 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
6015 return false;
6016
Arman Uguray24b4f382015-03-23 15:57:12 -07006017 /* If the current field length would exceed the total data
6018 * length, then it's invalid.
6019 */
Arman Uguray4117ed72015-03-23 15:57:14 -07006020 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07006021 return false;
6022 }
6023
6024 return true;
6025}
6026
Arman Uguray24b4f382015-03-23 15:57:12 -07006027static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6028 u16 opcode)
6029{
6030 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006031 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07006032 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006033 struct adv_info *adv_instance, *n;
6034 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006035
6036 BT_DBG("status %d", status);
6037
6038 hci_dev_lock(hdev);
6039
6040 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6041
Florian Grandelfffd38b2015-06-18 03:16:47 +02006042 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6043 if (!adv_instance->pending)
6044 continue;
6045
6046 if (!status) {
6047 adv_instance->pending = false;
6048 continue;
6049 }
6050
6051 instance = adv_instance->instance;
6052
6053 if (hdev->cur_adv_instance == instance)
6054 cancel_adv_timeout(hdev);
6055
6056 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006057 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006058 }
6059
6060 if (!cmd)
6061 goto unlock;
6062
Florian Grandelfffd38b2015-06-18 03:16:47 +02006063 cp = cmd->param;
6064 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006065
6066 if (status)
6067 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6068 mgmt_status(status));
6069 else
6070 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6071 mgmt_status(status), &rp, sizeof(rp));
6072
6073 mgmt_pending_remove(cmd);
6074
6075unlock:
6076 hci_dev_unlock(hdev);
6077}
6078
6079static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6080 void *data, u16 data_len)
6081{
6082 struct mgmt_cp_add_advertising *cp = data;
6083 struct mgmt_rp_add_advertising rp;
6084 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006085 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006086 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006087 u16 timeout, duration;
6088 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6089 u8 schedule_instance = 0;
6090 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006091 int err;
6092 struct mgmt_pending_cmd *cmd;
6093 struct hci_request req;
6094
6095 BT_DBG("%s", hdev->name);
6096
6097 status = mgmt_le_support(hdev);
6098 if (status)
6099 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6100 status);
6101
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006102 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6103 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6104 MGMT_STATUS_INVALID_PARAMS);
6105
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006106 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6107 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6108 MGMT_STATUS_INVALID_PARAMS);
6109
Arman Uguray24b4f382015-03-23 15:57:12 -07006110 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006111 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006112 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006113
Florian Grandelfffd38b2015-06-18 03:16:47 +02006114 /* The current implementation only supports a subset of the specified
6115 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006116 */
6117 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006118 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006119 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6120 MGMT_STATUS_INVALID_PARAMS);
6121
6122 hci_dev_lock(hdev);
6123
Arman Uguray912098a2015-03-23 15:57:15 -07006124 if (timeout && !hdev_is_powered(hdev)) {
6125 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6126 MGMT_STATUS_REJECTED);
6127 goto unlock;
6128 }
6129
Arman Uguray24b4f382015-03-23 15:57:12 -07006130 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006131 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006132 pending_find(MGMT_OP_SET_LE, hdev)) {
6133 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6134 MGMT_STATUS_BUSY);
6135 goto unlock;
6136 }
6137
Arman Ugurayb44133f2015-03-25 18:53:41 -07006138 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006139 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006140 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006141 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6142 MGMT_STATUS_INVALID_PARAMS);
6143 goto unlock;
6144 }
6145
Florian Grandelfffd38b2015-06-18 03:16:47 +02006146 err = hci_add_adv_instance(hdev, cp->instance, flags,
6147 cp->adv_data_len, cp->data,
6148 cp->scan_rsp_len,
6149 cp->data + cp->adv_data_len,
6150 timeout, duration);
6151 if (err < 0) {
6152 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6153 MGMT_STATUS_FAILED);
6154 goto unlock;
6155 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006156
Florian Grandelfffd38b2015-06-18 03:16:47 +02006157 /* Only trigger an advertising added event if a new instance was
6158 * actually added.
6159 */
6160 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006161 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006162
Florian Grandelfffd38b2015-06-18 03:16:47 +02006163 if (hdev->cur_adv_instance == cp->instance) {
6164 /* If the currently advertised instance is being changed then
6165 * cancel the current advertising and schedule the next
6166 * instance. If there is only one instance then the overridden
6167 * advertising data will be visible right away.
6168 */
6169 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006170
Florian Grandelfffd38b2015-06-18 03:16:47 +02006171 next_instance = hci_get_next_instance(hdev, cp->instance);
6172 if (next_instance)
6173 schedule_instance = next_instance->instance;
6174 } else if (!hdev->adv_instance_timeout) {
6175 /* Immediately advertise the new instance if no other
6176 * instance is currently being advertised.
6177 */
6178 schedule_instance = cp->instance;
6179 }
Arman Uguray912098a2015-03-23 15:57:15 -07006180
Florian Grandelfffd38b2015-06-18 03:16:47 +02006181 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6182 * there is no instance to be advertised then we have no HCI
6183 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006184 */
6185 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006186 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6187 !schedule_instance) {
6188 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006189 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6190 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6191 goto unlock;
6192 }
6193
6194 /* We're good to go, update advertising data, parameters, and start
6195 * advertising.
6196 */
6197 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6198 data_len);
6199 if (!cmd) {
6200 err = -ENOMEM;
6201 goto unlock;
6202 }
6203
6204 hci_req_init(&req, hdev);
6205
Johan Hedbergf2252572015-11-18 12:49:20 +02006206 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006207
Florian Grandelfffd38b2015-06-18 03:16:47 +02006208 if (!err)
6209 err = hci_req_run(&req, add_advertising_complete);
6210
Arman Uguray24b4f382015-03-23 15:57:12 -07006211 if (err < 0)
6212 mgmt_pending_remove(cmd);
6213
6214unlock:
6215 hci_dev_unlock(hdev);
6216
6217 return err;
6218}
6219
Arman Ugurayda9293352015-03-23 15:57:13 -07006220static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6221 u16 opcode)
6222{
6223 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006224 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006225 struct mgmt_rp_remove_advertising rp;
6226
6227 BT_DBG("status %d", status);
6228
6229 hci_dev_lock(hdev);
6230
6231 /* A failure status here only means that we failed to disable
6232 * advertising. Otherwise, the advertising instance has been removed,
6233 * so report success.
6234 */
6235 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6236 if (!cmd)
6237 goto unlock;
6238
Florian Grandel01948332015-06-18 03:16:48 +02006239 cp = cmd->param;
6240 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006241
6242 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6243 &rp, sizeof(rp));
6244 mgmt_pending_remove(cmd);
6245
6246unlock:
6247 hci_dev_unlock(hdev);
6248}
6249
6250static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6251 void *data, u16 data_len)
6252{
6253 struct mgmt_cp_remove_advertising *cp = data;
6254 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006255 struct mgmt_pending_cmd *cmd;
6256 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006257 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006258
6259 BT_DBG("%s", hdev->name);
6260
Arman Ugurayda9293352015-03-23 15:57:13 -07006261 hci_dev_lock(hdev);
6262
Johan Hedberg952497b2015-06-18 21:05:31 +03006263 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006264 err = mgmt_cmd_status(sk, hdev->id,
6265 MGMT_OP_REMOVE_ADVERTISING,
6266 MGMT_STATUS_INVALID_PARAMS);
6267 goto unlock;
6268 }
6269
Arman Ugurayda9293352015-03-23 15:57:13 -07006270 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6271 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6272 pending_find(MGMT_OP_SET_LE, hdev)) {
6273 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6274 MGMT_STATUS_BUSY);
6275 goto unlock;
6276 }
6277
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006278 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006279 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6280 MGMT_STATUS_INVALID_PARAMS);
6281 goto unlock;
6282 }
6283
Florian Grandel01948332015-06-18 03:16:48 +02006284 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006285
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006286 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006287
Florian Grandel01948332015-06-18 03:16:48 +02006288 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006289 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006290
Florian Grandel01948332015-06-18 03:16:48 +02006291 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6292 * flag is set or the device isn't powered then we have no HCI
6293 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006294 */
Florian Grandel01948332015-06-18 03:16:48 +02006295 if (skb_queue_empty(&req.cmd_q) ||
6296 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006297 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006298 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006299 err = mgmt_cmd_complete(sk, hdev->id,
6300 MGMT_OP_REMOVE_ADVERTISING,
6301 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6302 goto unlock;
6303 }
6304
6305 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6306 data_len);
6307 if (!cmd) {
6308 err = -ENOMEM;
6309 goto unlock;
6310 }
6311
Arman Ugurayda9293352015-03-23 15:57:13 -07006312 err = hci_req_run(&req, remove_advertising_complete);
6313 if (err < 0)
6314 mgmt_pending_remove(cmd);
6315
6316unlock:
6317 hci_dev_unlock(hdev);
6318
6319 return err;
6320}
6321
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006322static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6323{
6324 u8 max_len = HCI_MAX_AD_LENGTH;
6325
6326 if (is_adv_data) {
6327 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6328 MGMT_ADV_FLAG_LIMITED_DISCOV |
6329 MGMT_ADV_FLAG_MANAGED_FLAGS))
6330 max_len -= 3;
6331
6332 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6333 max_len -= 3;
Michał Narajowski7c295c42016-09-18 12:50:02 +02006334 } else {
6335 /* at least 1 byte of name should fit in */
6336 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
6337 max_len -= 3;
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006338 }
6339
6340 return max_len;
6341}
6342
6343static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6344 void *data, u16 data_len)
6345{
6346 struct mgmt_cp_get_adv_size_info *cp = data;
6347 struct mgmt_rp_get_adv_size_info rp;
6348 u32 flags, supported_flags;
6349 int err;
6350
6351 BT_DBG("%s", hdev->name);
6352
6353 if (!lmp_le_capable(hdev))
6354 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6355 MGMT_STATUS_REJECTED);
6356
6357 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6358 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6359 MGMT_STATUS_INVALID_PARAMS);
6360
6361 flags = __le32_to_cpu(cp->flags);
6362
6363 /* The current implementation only supports a subset of the specified
6364 * flags.
6365 */
6366 supported_flags = get_supported_adv_flags(hdev);
6367 if (flags & ~supported_flags)
6368 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6369 MGMT_STATUS_INVALID_PARAMS);
6370
6371 rp.instance = cp->instance;
6372 rp.flags = cp->flags;
6373 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6374 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6375
6376 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6377 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6378
6379 return err;
6380}
6381
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006382static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006383 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006384 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006385 HCI_MGMT_NO_HDEV |
6386 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006387 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006388 HCI_MGMT_NO_HDEV |
6389 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006390 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006391 HCI_MGMT_NO_HDEV |
6392 HCI_MGMT_UNTRUSTED },
6393 { read_controller_info, MGMT_READ_INFO_SIZE,
6394 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006395 { set_powered, MGMT_SETTING_SIZE },
6396 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6397 { set_connectable, MGMT_SETTING_SIZE },
6398 { set_fast_connectable, MGMT_SETTING_SIZE },
6399 { set_bondable, MGMT_SETTING_SIZE },
6400 { set_link_security, MGMT_SETTING_SIZE },
6401 { set_ssp, MGMT_SETTING_SIZE },
6402 { set_hs, MGMT_SETTING_SIZE },
6403 { set_le, MGMT_SETTING_SIZE },
6404 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6405 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6406 { add_uuid, MGMT_ADD_UUID_SIZE },
6407 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006408 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6409 HCI_MGMT_VAR_LEN },
6410 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6411 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006412 { disconnect, MGMT_DISCONNECT_SIZE },
6413 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6414 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6415 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6416 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6417 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6418 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6419 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6420 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6421 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6422 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6423 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006424 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6425 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6426 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006427 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6428 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6429 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6430 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6431 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6432 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6433 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6434 { set_advertising, MGMT_SETTING_SIZE },
6435 { set_bredr, MGMT_SETTING_SIZE },
6436 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6437 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6438 { set_secure_conn, MGMT_SETTING_SIZE },
6439 { set_debug_keys, MGMT_SETTING_SIZE },
6440 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006441 { load_irks, MGMT_LOAD_IRKS_SIZE,
6442 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006443 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6444 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6445 { add_device, MGMT_ADD_DEVICE_SIZE },
6446 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006447 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6448 HCI_MGMT_VAR_LEN },
6449 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006450 HCI_MGMT_NO_HDEV |
6451 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006452 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006453 HCI_MGMT_UNCONFIGURED |
6454 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006455 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6456 HCI_MGMT_UNCONFIGURED },
6457 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6458 HCI_MGMT_UNCONFIGURED },
6459 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6460 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006461 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006462 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006463 HCI_MGMT_NO_HDEV |
6464 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006465 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006466 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6467 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006468 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006469 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006470 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006471 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6472 HCI_MGMT_UNTRUSTED },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006473};
6474
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006475void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006476{
Marcel Holtmannced85542015-03-14 19:27:56 -07006477 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006478
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006479 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6480 return;
6481
Marcel Holtmannf9207332015-03-14 19:27:55 -07006482 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006483 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006484 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6485 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6486 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006487 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006488 } else {
6489 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6490 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006491 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006492 }
6493 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006494 case HCI_AMP:
6495 ev.type = 0x02;
6496 break;
6497 default:
6498 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006499 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006500
6501 ev.bus = hdev->bus;
6502
6503 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6504 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006505}
6506
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006507void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006508{
Marcel Holtmannced85542015-03-14 19:27:56 -07006509 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006510 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006511
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006512 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6513 return;
6514
Marcel Holtmannf9207332015-03-14 19:27:55 -07006515 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006516 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006517 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006518
Marcel Holtmannf9207332015-03-14 19:27:55 -07006519 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6520 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6521 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006522 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006523 } else {
6524 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6525 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006526 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006527 }
6528 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006529 case HCI_AMP:
6530 ev.type = 0x02;
6531 break;
6532 default:
6533 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006534 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006535
6536 ev.bus = hdev->bus;
6537
6538 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6539 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006540}
6541
Andre Guedes6046dc32014-02-26 20:21:51 -03006542/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006543static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006544{
6545 struct hci_conn_params *p;
6546
6547 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006548 /* Needed for AUTO_OFF case where might not "really"
6549 * have been powered off.
6550 */
6551 list_del_init(&p->action);
6552
6553 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006554 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006555 case HCI_AUTO_CONN_ALWAYS:
6556 list_add(&p->action, &hdev->pend_le_conns);
6557 break;
6558 case HCI_AUTO_CONN_REPORT:
6559 list_add(&p->action, &hdev->pend_le_reports);
6560 break;
6561 default:
6562 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006563 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006564 }
6565}
6566
Johan Hedberg2ff13892015-11-25 16:15:44 +02006567void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006568{
6569 struct cmd_lookup match = { NULL, hdev };
6570
Johan Hedberg2ff13892015-11-25 16:15:44 +02006571 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006572
Johan Hedberg2ff13892015-11-25 16:15:44 +02006573 hci_dev_lock(hdev);
6574
6575 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006576 restart_le_actions(hdev);
6577 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006578 }
6579
Johan Hedberg229ab392013-03-15 17:06:53 -05006580 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6581
6582 new_settings(hdev, match.sk);
6583
Johan Hedberg229ab392013-03-15 17:06:53 -05006584 if (match.sk)
6585 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006586
6587 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006588}
6589
Johan Hedberg2ff13892015-11-25 16:15:44 +02006590void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006591{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006592 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006593 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006594
Johan Hedberg229ab392013-03-15 17:06:53 -05006595 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006596
6597 /* If the power off is because of hdev unregistration let
6598 * use the appropriate INVALID_INDEX status. Otherwise use
6599 * NOT_POWERED. We cover both scenarios here since later in
6600 * mgmt_index_removed() any hci_conn callbacks will have already
6601 * been triggered, potentially causing misleading DISCONNECTED
6602 * status responses.
6603 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006604 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006605 status = MGMT_STATUS_INVALID_INDEX;
6606 else
6607 status = MGMT_STATUS_NOT_POWERED;
6608
6609 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006610
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006611 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02006612 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6613 zero_cod, sizeof(zero_cod),
6614 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006615 ext_info_changed(hdev, NULL);
6616 }
Johan Hedberg229ab392013-03-15 17:06:53 -05006617
Johan Hedberg2ff13892015-11-25 16:15:44 +02006618 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006619
6620 if (match.sk)
6621 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006622}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006623
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006624void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006625{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006626 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006627 u8 status;
6628
Johan Hedberg333ae952015-03-17 13:48:47 +02006629 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006630 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006631 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006632
6633 if (err == -ERFKILL)
6634 status = MGMT_STATUS_RFKILLED;
6635 else
6636 status = MGMT_STATUS_FAILED;
6637
Johan Hedberga69e8372015-03-06 21:08:53 +02006638 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006639
6640 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006641}
6642
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006643void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6644 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006645{
Johan Hedberg86742e12011-11-07 23:13:38 +02006646 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006647
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006648 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006649
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006650 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006651 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006652 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006653 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006654 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006655 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006656
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006657 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006658}
Johan Hedbergf7520542011-01-20 12:34:39 +02006659
Johan Hedbergd7b25452014-05-23 13:19:53 +03006660static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6661{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006662 switch (ltk->type) {
6663 case SMP_LTK:
6664 case SMP_LTK_SLAVE:
6665 if (ltk->authenticated)
6666 return MGMT_LTK_AUTHENTICATED;
6667 return MGMT_LTK_UNAUTHENTICATED;
6668 case SMP_LTK_P256:
6669 if (ltk->authenticated)
6670 return MGMT_LTK_P256_AUTH;
6671 return MGMT_LTK_P256_UNAUTH;
6672 case SMP_LTK_P256_DEBUG:
6673 return MGMT_LTK_P256_DEBUG;
6674 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006675
6676 return MGMT_LTK_UNAUTHENTICATED;
6677}
6678
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006679void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006680{
6681 struct mgmt_ev_new_long_term_key ev;
6682
6683 memset(&ev, 0, sizeof(ev));
6684
Marcel Holtmann5192d302014-02-19 17:11:58 -08006685 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006686 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006687 * to store long term keys. Their addresses will change the
6688 * next time around.
6689 *
6690 * Only when a remote device provides an identity address
6691 * make sure the long term key is stored. If the remote
6692 * identity is known, the long term keys are internally
6693 * mapped to the identity address. So allow static random
6694 * and public addresses here.
6695 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006696 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6697 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6698 ev.store_hint = 0x00;
6699 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006700 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006701
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006702 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006703 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006704 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006705 ev.key.enc_size = key->enc_size;
6706 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006707 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006708
Johan Hedberg2ceba532014-06-16 19:25:16 +03006709 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006710 ev.key.master = 1;
6711
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006712 /* Make sure we copy only the significant bytes based on the
6713 * encryption key size, and set the rest of the value to zeroes.
6714 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006715 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006716 memset(ev.key.val + key->enc_size, 0,
6717 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006718
Marcel Holtmann083368f2013-10-15 14:26:29 -07006719 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006720}
6721
Johan Hedbergcad20c22015-10-12 13:36:19 +02006722void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006723{
6724 struct mgmt_ev_new_irk ev;
6725
6726 memset(&ev, 0, sizeof(ev));
6727
Johan Hedbergcad20c22015-10-12 13:36:19 +02006728 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006729
Johan Hedberg95fbac82014-02-19 15:18:31 +02006730 bacpy(&ev.rpa, &irk->rpa);
6731 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6732 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6733 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6734
6735 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6736}
6737
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006738void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6739 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006740{
6741 struct mgmt_ev_new_csrk ev;
6742
6743 memset(&ev, 0, sizeof(ev));
6744
6745 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006746 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006747 * to store signature resolving keys. Their addresses will change
6748 * the next time around.
6749 *
6750 * Only when a remote device provides an identity address
6751 * make sure the signature resolving key is stored. So allow
6752 * static random and public addresses here.
6753 */
6754 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6755 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6756 ev.store_hint = 0x00;
6757 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006758 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006759
6760 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6761 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006762 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006763 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6764
6765 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6766}
6767
Andre Guedesffb5a8272014-07-01 18:10:11 -03006768void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006769 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6770 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006771{
6772 struct mgmt_ev_new_conn_param ev;
6773
Johan Hedbergc103aea2014-07-02 17:37:34 +03006774 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6775 return;
6776
Andre Guedesffb5a8272014-07-01 18:10:11 -03006777 memset(&ev, 0, sizeof(ev));
6778 bacpy(&ev.addr.bdaddr, bdaddr);
6779 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006780 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006781 ev.min_interval = cpu_to_le16(min_interval);
6782 ev.max_interval = cpu_to_le16(max_interval);
6783 ev.latency = cpu_to_le16(latency);
6784 ev.timeout = cpu_to_le16(timeout);
6785
6786 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6787}
6788
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006789void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6790 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006791{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006792 char buf[512];
6793 struct mgmt_ev_device_connected *ev = (void *) buf;
6794 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006795
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006796 bacpy(&ev->addr.bdaddr, &conn->dst);
6797 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006798
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006799 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006800
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006801 /* We must ensure that the EIR Data fields are ordered and
6802 * unique. Keep it simple for now and avoid the problem by not
6803 * adding any BR/EDR data to the LE adv.
6804 */
6805 if (conn->le_adv_data_len > 0) {
6806 memcpy(&ev->eir[eir_len],
6807 conn->le_adv_data, conn->le_adv_data_len);
6808 eir_len = conn->le_adv_data_len;
6809 } else {
6810 if (name_len > 0)
6811 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6812 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006813
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006814 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006815 eir_len = eir_append_data(ev->eir, eir_len,
6816 EIR_CLASS_OF_DEV,
6817 conn->dev_class, 3);
6818 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006819
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006820 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006821
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006822 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6823 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006824}
6825
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006826static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006827{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006828 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006829
Johan Hedbergf5818c22014-12-05 13:36:02 +02006830 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006831
6832 *sk = cmd->sk;
6833 sock_hold(*sk);
6834
Johan Hedberga664b5b2011-02-19 12:06:02 -03006835 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006836}
6837
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006838static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006839{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006840 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006841 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006842
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006843 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6844
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006845 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006846 mgmt_pending_remove(cmd);
6847}
6848
Johan Hedberg84c61d92014-08-01 11:13:30 +03006849bool mgmt_powering_down(struct hci_dev *hdev)
6850{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006851 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006852 struct mgmt_mode *cp;
6853
Johan Hedberg333ae952015-03-17 13:48:47 +02006854 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006855 if (!cmd)
6856 return false;
6857
6858 cp = cmd->param;
6859 if (!cp->val)
6860 return true;
6861
6862 return false;
6863}
6864
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006865void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006866 u8 link_type, u8 addr_type, u8 reason,
6867 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006868{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006869 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006870 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006871
Johan Hedberg84c61d92014-08-01 11:13:30 +03006872 /* The connection is still in hci_conn_hash so test for 1
6873 * instead of 0 to know if this is the last one.
6874 */
6875 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6876 cancel_delayed_work(&hdev->power_off);
6877 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006878 }
6879
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006880 if (!mgmt_connected)
6881 return;
6882
Andre Guedes57eb7762013-10-30 19:01:41 -03006883 if (link_type != ACL_LINK && link_type != LE_LINK)
6884 return;
6885
Johan Hedberg744cf192011-11-08 20:40:14 +02006886 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006887
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006888 bacpy(&ev.addr.bdaddr, bdaddr);
6889 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6890 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006891
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006892 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006893
6894 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006895 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006896
Johan Hedberg124f6e32012-02-09 13:50:12 +02006897 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006898 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006899}
6900
Marcel Holtmann78929242013-10-06 23:55:47 -07006901void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6902 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006903{
Andre Guedes3655bba2013-10-30 19:01:40 -03006904 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6905 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006906 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006907
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006908 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6909 hdev);
6910
Johan Hedberg333ae952015-03-17 13:48:47 +02006911 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006912 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006913 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006914
Andre Guedes3655bba2013-10-30 19:01:40 -03006915 cp = cmd->param;
6916
6917 if (bacmp(bdaddr, &cp->addr.bdaddr))
6918 return;
6919
6920 if (cp->addr.type != bdaddr_type)
6921 return;
6922
Johan Hedbergf5818c22014-12-05 13:36:02 +02006923 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006924 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006925}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006926
Marcel Holtmann445608d2013-10-06 23:55:48 -07006927void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6928 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006929{
6930 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006931
Johan Hedberg84c61d92014-08-01 11:13:30 +03006932 /* The connection is still in hci_conn_hash so test for 1
6933 * instead of 0 to know if this is the last one.
6934 */
6935 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6936 cancel_delayed_work(&hdev->power_off);
6937 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006938 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006939
Johan Hedberg4c659c32011-11-07 23:13:39 +02006940 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006941 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006942 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006943
Marcel Holtmann445608d2013-10-06 23:55:48 -07006944 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006945}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006946
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006947void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006948{
6949 struct mgmt_ev_pin_code_request ev;
6950
Johan Hedbergd8457692012-02-17 14:24:57 +02006951 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006952 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006953 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006954
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006955 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006956}
6957
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006958void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6959 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006960{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006961 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006962
Johan Hedberg333ae952015-03-17 13:48:47 +02006963 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006964 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006965 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006966
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006967 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006968 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006969}
6970
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006971void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6972 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006973{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006974 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006975
Johan Hedberg333ae952015-03-17 13:48:47 +02006976 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006977 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006978 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006979
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006980 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006981 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006982}
Johan Hedberga5c29682011-02-19 12:05:57 -03006983
Johan Hedberg744cf192011-11-08 20:40:14 +02006984int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006985 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006986 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006987{
6988 struct mgmt_ev_user_confirm_request ev;
6989
Johan Hedberg744cf192011-11-08 20:40:14 +02006990 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006991
Johan Hedberg272d90d2012-02-09 15:26:12 +02006992 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006993 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006994 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006995 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006996
Johan Hedberg744cf192011-11-08 20:40:14 +02006997 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006998 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006999}
7000
Johan Hedberg272d90d2012-02-09 15:26:12 +02007001int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007002 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007003{
7004 struct mgmt_ev_user_passkey_request ev;
7005
7006 BT_DBG("%s", hdev->name);
7007
Johan Hedberg272d90d2012-02-09 15:26:12 +02007008 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007009 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007010
7011 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007012 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007013}
7014
Brian Gix0df4c182011-11-16 13:53:13 -08007015static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007016 u8 link_type, u8 addr_type, u8 status,
7017 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007018{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007019 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007020
Johan Hedberg333ae952015-03-17 13:48:47 +02007021 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007022 if (!cmd)
7023 return -ENOENT;
7024
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007025 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007026 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007027
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007028 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007029}
7030
Johan Hedberg744cf192011-11-08 20:40:14 +02007031int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007032 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007033{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007034 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007035 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007036}
7037
Johan Hedberg272d90d2012-02-09 15:26:12 +02007038int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007039 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007040{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007041 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007042 status,
7043 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007044}
Johan Hedberg2a611692011-02-19 12:06:00 -03007045
Brian Gix604086b2011-11-23 08:28:33 -08007046int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007047 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007048{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007049 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007050 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007051}
7052
Johan Hedberg272d90d2012-02-09 15:26:12 +02007053int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007054 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007055{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007056 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007057 status,
7058 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007059}
7060
Johan Hedberg92a25252012-09-06 18:39:26 +03007061int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7062 u8 link_type, u8 addr_type, u32 passkey,
7063 u8 entered)
7064{
7065 struct mgmt_ev_passkey_notify ev;
7066
7067 BT_DBG("%s", hdev->name);
7068
7069 bacpy(&ev.addr.bdaddr, bdaddr);
7070 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7071 ev.passkey = __cpu_to_le32(passkey);
7072 ev.entered = entered;
7073
7074 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7075}
7076
Johan Hedberge1e930f2014-09-08 17:09:49 -07007077void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007078{
7079 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007080 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007081 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007082
Johan Hedberge1e930f2014-09-08 17:09:49 -07007083 bacpy(&ev.addr.bdaddr, &conn->dst);
7084 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7085 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007086
Johan Hedberge1e930f2014-09-08 17:09:49 -07007087 cmd = find_pairing(conn);
7088
7089 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7090 cmd ? cmd->sk : NULL);
7091
Johan Hedberga511b352014-12-11 21:45:45 +02007092 if (cmd) {
7093 cmd->cmd_complete(cmd, status);
7094 mgmt_pending_remove(cmd);
7095 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007096}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007097
Marcel Holtmann464996a2013-10-15 14:26:24 -07007098void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007099{
7100 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007101 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007102
7103 if (status) {
7104 u8 mgmt_err = mgmt_status(status);
7105 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007106 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007107 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007108 }
7109
Marcel Holtmann464996a2013-10-15 14:26:24 -07007110 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007111 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007112 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007113 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007114
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007115 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007116 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007117
Johan Hedberg47990ea2012-02-22 11:58:37 +02007118 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007119 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007120
7121 if (match.sk)
7122 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007123}
7124
Johan Hedberg890ea892013-03-15 17:06:52 -05007125static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007126{
Johan Hedberg890ea892013-03-15 17:06:52 -05007127 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007128 struct hci_cp_write_eir cp;
7129
Johan Hedberg976eb202012-10-24 21:12:01 +03007130 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007131 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007132
Johan Hedbergc80da272012-02-22 15:38:48 +02007133 memset(hdev->eir, 0, sizeof(hdev->eir));
7134
Johan Hedbergcacaf522012-02-21 00:52:42 +02007135 memset(&cp, 0, sizeof(cp));
7136
Johan Hedberg890ea892013-03-15 17:06:52 -05007137 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007138}
7139
Marcel Holtmann3e248562013-10-15 14:26:25 -07007140void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007141{
7142 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007143 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007144 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007145
7146 if (status) {
7147 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007148
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007149 if (enable && hci_dev_test_and_clear_flag(hdev,
7150 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007151 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007152 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007153 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007154
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007155 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7156 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007157 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007158 }
7159
7160 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007161 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007162 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007163 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007164 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007165 changed = hci_dev_test_and_clear_flag(hdev,
7166 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007167 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007168 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007169 }
7170
7171 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7172
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007173 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007174 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007175
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007176 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007177 sock_put(match.sk);
7178
Johan Hedberg890ea892013-03-15 17:06:52 -05007179 hci_req_init(&req, hdev);
7180
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007181 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7182 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007183 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7184 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007185 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007186 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007187 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007188 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007189
7190 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007191}
7192
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007193static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007194{
7195 struct cmd_lookup *match = data;
7196
Johan Hedberg90e70452012-02-23 23:09:40 +02007197 if (match->sk == NULL) {
7198 match->sk = cmd->sk;
7199 sock_hold(match->sk);
7200 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007201}
7202
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007203void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7204 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007205{
Johan Hedberg90e70452012-02-23 23:09:40 +02007206 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007207
Johan Hedberg92da6092013-03-15 17:06:55 -05007208 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7209 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7210 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007211
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007212 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007213 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7214 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007215 ext_info_changed(hdev, NULL);
7216 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007217
7218 if (match.sk)
7219 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007220}
7221
Marcel Holtmann7667da32013-10-15 14:26:27 -07007222void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007223{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007224 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007225 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007226
Johan Hedberg13928972013-03-15 17:07:00 -05007227 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007228 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007229
7230 memset(&ev, 0, sizeof(ev));
7231 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007232 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007233
Johan Hedberg333ae952015-03-17 13:48:47 +02007234 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007235 if (!cmd) {
7236 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007237
Johan Hedberg13928972013-03-15 17:07:00 -05007238 /* If this is a HCI command related to powering on the
7239 * HCI dev don't send any mgmt signals.
7240 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007241 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007242 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007243 }
7244
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007245 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7246 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007247 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007248}
Szymon Jancc35938b2011-03-22 13:12:21 +01007249
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007250static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7251{
7252 int i;
7253
7254 for (i = 0; i < uuid_count; i++) {
7255 if (!memcmp(uuid, uuids[i], 16))
7256 return true;
7257 }
7258
7259 return false;
7260}
7261
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007262static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7263{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007264 u16 parsed = 0;
7265
7266 while (parsed < eir_len) {
7267 u8 field_len = eir[0];
7268 u8 uuid[16];
7269 int i;
7270
7271 if (field_len == 0)
7272 break;
7273
7274 if (eir_len - parsed < field_len + 1)
7275 break;
7276
7277 switch (eir[1]) {
7278 case EIR_UUID16_ALL:
7279 case EIR_UUID16_SOME:
7280 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007281 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007282 uuid[13] = eir[i + 3];
7283 uuid[12] = eir[i + 2];
7284 if (has_uuid(uuid, uuid_count, uuids))
7285 return true;
7286 }
7287 break;
7288 case EIR_UUID32_ALL:
7289 case EIR_UUID32_SOME:
7290 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007291 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007292 uuid[15] = eir[i + 5];
7293 uuid[14] = eir[i + 4];
7294 uuid[13] = eir[i + 3];
7295 uuid[12] = eir[i + 2];
7296 if (has_uuid(uuid, uuid_count, uuids))
7297 return true;
7298 }
7299 break;
7300 case EIR_UUID128_ALL:
7301 case EIR_UUID128_SOME:
7302 for (i = 0; i + 17 <= field_len; i += 16) {
7303 memcpy(uuid, eir + i + 2, 16);
7304 if (has_uuid(uuid, uuid_count, uuids))
7305 return true;
7306 }
7307 break;
7308 }
7309
7310 parsed += field_len + 1;
7311 eir += field_len + 1;
7312 }
7313
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007314 return false;
7315}
7316
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007317static void restart_le_scan(struct hci_dev *hdev)
7318{
7319 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007320 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007321 return;
7322
7323 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7324 hdev->discovery.scan_start +
7325 hdev->discovery.scan_duration))
7326 return;
7327
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007328 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007329 DISCOV_LE_RESTART_DELAY);
7330}
7331
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007332static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7333 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7334{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007335 /* If a RSSI threshold has been specified, and
7336 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7337 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7338 * is set, let it through for further processing, as we might need to
7339 * restart the scan.
7340 *
7341 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7342 * the results are also dropped.
7343 */
7344 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7345 (rssi == HCI_RSSI_INVALID ||
7346 (rssi < hdev->discovery.rssi &&
7347 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7348 return false;
7349
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007350 if (hdev->discovery.uuid_count != 0) {
7351 /* If a list of UUIDs is provided in filter, results with no
7352 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007353 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007354 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7355 hdev->discovery.uuids) &&
7356 !eir_has_uuids(scan_rsp, scan_rsp_len,
7357 hdev->discovery.uuid_count,
7358 hdev->discovery.uuids))
7359 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007360 }
7361
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007362 /* If duplicate filtering does not report RSSI changes, then restart
7363 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007364 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007365 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7366 restart_le_scan(hdev);
7367
7368 /* Validate RSSI value against the RSSI threshold once more. */
7369 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7370 rssi < hdev->discovery.rssi)
7371 return false;
7372 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007373
7374 return true;
7375}
7376
Marcel Holtmann901801b2013-10-06 23:55:51 -07007377void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007378 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7379 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007380{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007381 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007382 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007383 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007384
Johan Hedberg75ce2082014-07-02 22:42:01 +03007385 /* Don't send events for a non-kernel initiated discovery. With
7386 * LE one exception is if we have pend_le_reports > 0 in which
7387 * case we're doing passive scanning and want these events.
7388 */
7389 if (!hci_discovery_active(hdev)) {
7390 if (link_type == ACL_LINK)
7391 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007392 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007393 return;
7394 }
Andre Guedes12602d02013-04-30 15:29:40 -03007395
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007396 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007397 /* We are using service discovery */
7398 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7399 scan_rsp_len))
7400 return;
7401 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007402
Johan Hedberg78b781c2016-01-05 13:19:32 +02007403 if (hdev->discovery.limited) {
7404 /* Check for limited discoverable bit */
7405 if (dev_class) {
7406 if (!(dev_class[1] & 0x20))
7407 return;
7408 } else {
7409 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7410 if (!flags || !(flags[0] & LE_AD_LIMITED))
7411 return;
7412 }
7413 }
7414
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007415 /* Make sure that the buffer is big enough. The 5 extra bytes
7416 * are for the potential CoD field.
7417 */
7418 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007419 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007420
Johan Hedberg1dc06092012-01-15 21:01:23 +02007421 memset(buf, 0, sizeof(buf));
7422
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007423 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7424 * RSSI value was reported as 0 when not available. This behavior
7425 * is kept when using device discovery. This is required for full
7426 * backwards compatibility with the API.
7427 *
7428 * However when using service discovery, the value 127 will be
7429 * returned when the RSSI is not available.
7430 */
Szymon Janc91200e92015-01-22 16:57:05 +01007431 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7432 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007433 rssi = 0;
7434
Johan Hedberg841c5642014-07-07 12:45:54 +03007435 bacpy(&ev->addr.bdaddr, bdaddr);
7436 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007437 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007438 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007439
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007440 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007441 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007442 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007443
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007444 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7445 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007446 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007447 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007448
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007449 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007450 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007451 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007452
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007453 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7454 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007455
Marcel Holtmann901801b2013-10-06 23:55:51 -07007456 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007457}
Johan Hedberga88a9652011-03-30 13:18:12 +03007458
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007459void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7460 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007461{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007462 struct mgmt_ev_device_found *ev;
7463 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7464 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007465
Johan Hedbergb644ba32012-01-17 21:48:47 +02007466 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007467
Johan Hedbergb644ba32012-01-17 21:48:47 +02007468 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007469
Johan Hedbergb644ba32012-01-17 21:48:47 +02007470 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007471 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007472 ev->rssi = rssi;
7473
7474 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007475 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007476
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007477 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007478
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007479 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007480}
Johan Hedberg314b2382011-04-27 10:29:57 -04007481
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007482void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007483{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007484 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007485
Andre Guedes343fb142011-11-22 17:14:19 -03007486 BT_DBG("%s discovering %u", hdev->name, discovering);
7487
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007488 memset(&ev, 0, sizeof(ev));
7489 ev.type = hdev->discovery.type;
7490 ev.discovering = discovering;
7491
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007492 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007493}
Antti Julku5e762442011-08-25 16:48:02 +03007494
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007495static struct hci_mgmt_chan chan = {
7496 .channel = HCI_CHANNEL_CONTROL,
7497 .handler_count = ARRAY_SIZE(mgmt_handlers),
7498 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007499 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007500};
7501
7502int mgmt_init(void)
7503{
7504 return hci_mgmt_chan_register(&chan);
7505}
7506
7507void mgmt_exit(void)
7508{
7509 hci_mgmt_chan_unregister(&chan);
7510}