blob: 74179b92ef2285830626e5d943f724947a82ebd3 [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 Holtmannedd38962014-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Holtmann08dc0e92015-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200862
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300863 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200905 rp = kmalloc(sizeof(*rp) + eir_len, GFP_KERNEL);
906 if (!rp)
907 return -ENOMEM;
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200908
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200909 memset(rp, 0, sizeof(*rp) + eir_len);
910
911 rp->eir_len = cpu_to_le16(eir_len);
912 memcpy(rp->eir, buff, eir_len);
913
914 bacpy(&rp->bdaddr, &hdev->bdaddr);
915
916 rp->version = hdev->hci_ver;
917 rp->manufacturer = cpu_to_le16(hdev->manufacturer);
918
919 rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
920 rp->current_settings = cpu_to_le32(get_current_settings(hdev));
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200921
922 hci_dev_unlock(hdev);
923
924 /* If this command is called at least once, then the events
925 * for class of device and local name changes are disabled
926 * and only the new extended controller information event
927 * is used.
928 */
929 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
930 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
931 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
932
Michał Narajowski8a0c9f42016-09-01 16:46:24 +0200933 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
934 sizeof(*rp) + eir_len);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200935}
936
937static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
938{
939 struct mgmt_ev_ext_info_changed ev;
940
941 ev.eir_len = cpu_to_le16(0);
942
943 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, &ev,
944 sizeof(ev), HCI_MGMT_EXT_INFO_EVENTS, skip);
945}
946
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200947static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200948{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200949 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200950
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200951 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
952 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200953}
954
Marcel Holtmann1904a852015-01-11 13:50:44 -0800955static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200956{
957 BT_DBG("%s status 0x%02x", hdev->name, status);
958
Johan Hedberga3172b72014-02-28 09:33:44 +0200959 if (hci_conn_count(hdev) == 0) {
960 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200961 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200962 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200963}
964
Johan Hedbergf2252572015-11-18 12:49:20 +0200965void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700966{
967 struct mgmt_ev_advertising_added ev;
968
969 ev.instance = instance;
970
971 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
972}
973
Johan Hedbergf2252572015-11-18 12:49:20 +0200974void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
975 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700976{
977 struct mgmt_ev_advertising_removed ev;
978
979 ev.instance = instance;
980
981 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
982}
983
Florian Grandel7816b822015-06-18 03:16:45 +0200984static void cancel_adv_timeout(struct hci_dev *hdev)
985{
986 if (hdev->adv_instance_timeout) {
987 hdev->adv_instance_timeout = 0;
988 cancel_delayed_work(&hdev->adv_instance_expire);
989 }
990}
991
Johan Hedberg8b064a32014-02-24 14:52:22 +0200992static int clean_up_hci_state(struct hci_dev *hdev)
993{
994 struct hci_request req;
995 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300996 bool discov_stopped;
997 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200998
999 hci_req_init(&req, hdev);
1000
1001 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1002 test_bit(HCI_PSCAN, &hdev->flags)) {
1003 u8 scan = 0x00;
1004 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1005 }
1006
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001007 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -07001008
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001009 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001010 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001011
Johan Hedberg2154d3f2015-11-11 08:30:45 +02001012 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001013
1014 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03001015 /* 0x15 == Terminated due to Power Off */
1016 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001017 }
1018
Johan Hedberg23a48092014-07-08 16:05:06 +03001019 err = hci_req_run(&req, clean_up_hci_complete);
1020 if (!err && discov_stopped)
1021 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1022
1023 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001024}
1025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001026static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001027 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001028{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001029 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001030 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001031 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001033 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedberga7e80f22013-01-09 16:05:19 +02001035 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001036 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1037 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001038
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001039 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
Johan Hedberg333ae952015-03-17 13:48:47 +02001041 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001042 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1043 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001044 goto failed;
1045 }
1046
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001047 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001048 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049 goto failed;
1050 }
1051
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1053 if (!cmd) {
1054 err = -ENOMEM;
1055 goto failed;
1056 }
1057
Johan Hedberg8b064a32014-02-24 14:52:22 +02001058 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001059 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001060 err = 0;
1061 } else {
1062 /* Disconnect connections, stop scans, etc */
1063 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001064 if (!err)
1065 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1066 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001067
Johan Hedberg8b064a32014-02-24 14:52:22 +02001068 /* ENODATA means there were no HCI commands queued */
1069 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001070 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001071 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1072 err = 0;
1073 }
1074 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001075
1076failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001077 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001078 return err;
1079}
1080
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001081static int new_settings(struct hci_dev *hdev, struct sock *skip)
1082{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001083 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001084
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001085 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1086 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001087}
1088
Johan Hedberg91a668b2014-07-09 13:28:26 +03001089int mgmt_new_settings(struct hci_dev *hdev)
1090{
1091 return new_settings(hdev, NULL);
1092}
1093
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001094struct cmd_lookup {
1095 struct sock *sk;
1096 struct hci_dev *hdev;
1097 u8 mgmt_status;
1098};
1099
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001100static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001101{
1102 struct cmd_lookup *match = data;
1103
1104 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1105
1106 list_del(&cmd->list);
1107
1108 if (match->sk == NULL) {
1109 match->sk = cmd->sk;
1110 sock_hold(match->sk);
1111 }
1112
1113 mgmt_pending_free(cmd);
1114}
1115
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001116static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001117{
1118 u8 *status = data;
1119
Johan Hedberga69e8372015-03-06 21:08:53 +02001120 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001121 mgmt_pending_remove(cmd);
1122}
1123
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001124static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001125{
1126 if (cmd->cmd_complete) {
1127 u8 *status = data;
1128
1129 cmd->cmd_complete(cmd, *status);
1130 mgmt_pending_remove(cmd);
1131
1132 return;
1133 }
1134
1135 cmd_status_rsp(cmd, data);
1136}
1137
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001138static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001139{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001140 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1141 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001142}
1143
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001144static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001145{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001146 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1147 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001148}
1149
Johan Hedberge6fe7982013-10-02 15:45:22 +03001150static u8 mgmt_bredr_support(struct hci_dev *hdev)
1151{
1152 if (!lmp_bredr_capable(hdev))
1153 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001154 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001155 return MGMT_STATUS_REJECTED;
1156 else
1157 return MGMT_STATUS_SUCCESS;
1158}
1159
1160static u8 mgmt_le_support(struct hci_dev *hdev)
1161{
1162 if (!lmp_le_capable(hdev))
1163 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001164 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001165 return MGMT_STATUS_REJECTED;
1166 else
1167 return MGMT_STATUS_SUCCESS;
1168}
1169
Johan Hedbergaed1a882015-11-22 17:24:44 +03001170void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001171{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001172 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001173
1174 BT_DBG("status 0x%02x", status);
1175
1176 hci_dev_lock(hdev);
1177
Johan Hedberg333ae952015-03-17 13:48:47 +02001178 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001179 if (!cmd)
1180 goto unlock;
1181
1182 if (status) {
1183 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001184 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001185 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001186 goto remove_cmd;
1187 }
1188
Johan Hedbergaed1a882015-11-22 17:24:44 +03001189 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1190 hdev->discov_timeout > 0) {
1191 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1192 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001193 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001194
1195 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001196 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001197
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001198remove_cmd:
1199 mgmt_pending_remove(cmd);
1200
1201unlock:
1202 hci_dev_unlock(hdev);
1203}
1204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001205static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001206 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001207{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001208 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001209 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001210 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001211 int err;
1212
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001213 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001214
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001215 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1216 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001217 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1218 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001219
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001220 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001221 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1222 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001223
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001224 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001225
1226 /* Disabling discoverable requires that no timeout is set,
1227 * and enabling limited discoverable requires a timeout.
1228 */
1229 if ((cp->val == 0x00 && timeout > 0) ||
1230 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001231 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1232 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001233
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001234 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001235
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001236 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001237 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1238 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001239 goto failed;
1240 }
1241
Johan Hedberg333ae952015-03-17 13:48:47 +02001242 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1243 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001244 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1245 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001246 goto failed;
1247 }
1248
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001249 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001250 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1251 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001252 goto failed;
1253 }
1254
1255 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001256 bool changed = false;
1257
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001258 /* Setting limited discoverable when powered off is
1259 * not a valid operation since it requires a timeout
1260 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1261 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001262 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001263 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001264 changed = true;
1265 }
1266
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001267 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001268 if (err < 0)
1269 goto failed;
1270
1271 if (changed)
1272 err = new_settings(hdev, sk);
1273
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001274 goto failed;
1275 }
1276
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001277 /* If the current mode is the same, then just update the timeout
1278 * value with the new value. And if only the timeout gets updated,
1279 * then no need for any HCI transactions.
1280 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001281 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1282 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1283 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001284 cancel_delayed_work(&hdev->discov_off);
1285 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001286
Marcel Holtmann36261542013-10-15 08:28:51 -07001287 if (cp->val && hdev->discov_timeout > 0) {
1288 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001289 queue_delayed_work(hdev->req_workqueue,
1290 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001291 }
1292
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001293 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001294 goto failed;
1295 }
1296
1297 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1298 if (!cmd) {
1299 err = -ENOMEM;
1300 goto failed;
1301 }
1302
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001303 /* Cancel any potential discoverable timeout that might be
1304 * still active and store new timeout value. The arming of
1305 * the timeout happens in the complete handler.
1306 */
1307 cancel_delayed_work(&hdev->discov_off);
1308 hdev->discov_timeout = timeout;
1309
Johan Hedbergaed1a882015-11-22 17:24:44 +03001310 if (cp->val)
1311 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1312 else
1313 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1314
Johan Hedbergb456f872013-10-19 23:38:22 +03001315 /* Limited discoverable mode */
1316 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001317 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001318 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001319 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001320
Johan Hedbergaed1a882015-11-22 17:24:44 +03001321 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1322 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001323
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001324failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001325 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001326 return err;
1327}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001328
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001329void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001330{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001331 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001332
1333 BT_DBG("status 0x%02x", status);
1334
1335 hci_dev_lock(hdev);
1336
Johan Hedberg333ae952015-03-17 13:48:47 +02001337 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001338 if (!cmd)
1339 goto unlock;
1340
Johan Hedberg37438c12013-10-14 16:20:05 +03001341 if (status) {
1342 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001343 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001344 goto remove_cmd;
1345 }
1346
Johan Hedberg2b76f452013-03-15 17:07:04 -05001347 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001348 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001349
Johan Hedberg37438c12013-10-14 16:20:05 +03001350remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001351 mgmt_pending_remove(cmd);
1352
1353unlock:
1354 hci_dev_unlock(hdev);
1355}
1356
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001357static int set_connectable_update_settings(struct hci_dev *hdev,
1358 struct sock *sk, u8 val)
1359{
1360 bool changed = false;
1361 int err;
1362
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001363 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001364 changed = true;
1365
1366 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001367 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001368 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001369 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1370 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001371 }
1372
1373 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1374 if (err < 0)
1375 return err;
1376
Johan Hedberg562064e2014-07-08 16:35:34 +03001377 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001378 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001379 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001380 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001381 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001382
1383 return 0;
1384}
1385
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001386static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001387 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001388{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001389 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001390 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001391 int err;
1392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001394
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001395 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1396 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001397 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1398 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001399
Johan Hedberga7e80f22013-01-09 16:05:19 +02001400 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001401 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1402 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001403
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001404 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001405
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001406 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001407 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001408 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001409 }
1410
Johan Hedberg333ae952015-03-17 13:48:47 +02001411 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1412 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001413 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1414 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001415 goto failed;
1416 }
1417
Johan Hedberg73f22f62010-12-29 16:00:25 +02001418 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1419 if (!cmd) {
1420 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001421 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001422 }
1423
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001424 if (cp->val) {
1425 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1426 } else {
1427 if (hdev->discov_timeout > 0)
1428 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001429
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001430 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1431 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1432 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001433 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001434
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001435 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1436 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001437
1438failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001440 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001441}
1442
Johan Hedbergb2939472014-07-30 09:22:23 +03001443static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001444 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001445{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001446 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001447 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001448 int err;
1449
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001450 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001451
Johan Hedberga7e80f22013-01-09 16:05:19 +02001452 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001453 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1454 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001456 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001457
1458 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001459 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001460 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001461 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001462
Johan Hedbergb2939472014-07-30 09:22:23 +03001463 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001464 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001465 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001466
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001467 if (changed) {
1468 /* In limited privacy mode the change of bondable mode
1469 * may affect the local advertising address.
1470 */
1471 if (hdev_is_powered(hdev) &&
1472 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1473 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1474 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1475 queue_work(hdev->req_workqueue,
1476 &hdev->discoverable_update);
1477
Marcel Holtmann55594352013-10-06 16:11:57 -07001478 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001479 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001480
Marcel Holtmann55594352013-10-06 16:11:57 -07001481unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001482 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001483 return err;
1484}
1485
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001486static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1487 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001488{
1489 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001490 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001491 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001492 int err;
1493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001494 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001495
Johan Hedberge6fe7982013-10-02 15:45:22 +03001496 status = mgmt_bredr_support(hdev);
1497 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001498 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1499 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001500
Johan Hedberga7e80f22013-01-09 16:05:19 +02001501 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001502 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1503 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001504
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001505 hci_dev_lock(hdev);
1506
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001507 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001508 bool changed = false;
1509
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001510 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001511 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001512 changed = true;
1513 }
1514
1515 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1516 if (err < 0)
1517 goto failed;
1518
1519 if (changed)
1520 err = new_settings(hdev, sk);
1521
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001522 goto failed;
1523 }
1524
Johan Hedberg333ae952015-03-17 13:48:47 +02001525 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001526 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1527 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001528 goto failed;
1529 }
1530
1531 val = !!cp->val;
1532
1533 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1534 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1535 goto failed;
1536 }
1537
1538 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1539 if (!cmd) {
1540 err = -ENOMEM;
1541 goto failed;
1542 }
1543
1544 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1545 if (err < 0) {
1546 mgmt_pending_remove(cmd);
1547 goto failed;
1548 }
1549
1550failed:
1551 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001552 return err;
1553}
1554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001555static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001556{
1557 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001558 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001559 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001560 int err;
1561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001562 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001563
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001564 status = mgmt_bredr_support(hdev);
1565 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001567
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001568 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001569 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1570 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001571
Johan Hedberga7e80f22013-01-09 16:05:19 +02001572 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001573 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1574 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001575
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001576 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001577
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001578 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001579 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001580
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001581 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001582 changed = !hci_dev_test_and_set_flag(hdev,
1583 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001584 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001585 changed = hci_dev_test_and_clear_flag(hdev,
1586 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001587 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001588 changed = hci_dev_test_and_clear_flag(hdev,
1589 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001590 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001591 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001592 }
1593
1594 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1595 if (err < 0)
1596 goto failed;
1597
1598 if (changed)
1599 err = new_settings(hdev, sk);
1600
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001601 goto failed;
1602 }
1603
Johan Hedberg333ae952015-03-17 13:48:47 +02001604 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001605 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1606 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001607 goto failed;
1608 }
1609
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001610 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001611 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1612 goto failed;
1613 }
1614
1615 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1616 if (!cmd) {
1617 err = -ENOMEM;
1618 goto failed;
1619 }
1620
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001621 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001622 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1623 sizeof(cp->val), &cp->val);
1624
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001625 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001626 if (err < 0) {
1627 mgmt_pending_remove(cmd);
1628 goto failed;
1629 }
1630
1631failed:
1632 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001633 return err;
1634}
1635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001636static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001637{
1638 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001639 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001640 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001641 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001642
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001644
Johan Hedberge6fe7982013-10-02 15:45:22 +03001645 status = mgmt_bredr_support(hdev);
1646 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001647 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001648
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001649 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001650 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1651 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001652
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001653 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001654 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1655 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001656
Johan Hedberga7e80f22013-01-09 16:05:19 +02001657 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001658 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1659 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001660
Marcel Holtmannee392692013-10-01 22:59:23 -07001661 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001662
Johan Hedberg333ae952015-03-17 13:48:47 +02001663 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001664 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1665 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001666 goto unlock;
1667 }
1668
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001669 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001670 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001671 } else {
1672 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001673 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1674 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001675 goto unlock;
1676 }
1677
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001678 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001679 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001680
1681 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1682 if (err < 0)
1683 goto unlock;
1684
1685 if (changed)
1686 err = new_settings(hdev, sk);
1687
1688unlock:
1689 hci_dev_unlock(hdev);
1690 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001691}
1692
Marcel Holtmann1904a852015-01-11 13:50:44 -08001693static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001694{
1695 struct cmd_lookup match = { NULL, hdev };
1696
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301697 hci_dev_lock(hdev);
1698
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001699 if (status) {
1700 u8 mgmt_err = mgmt_status(status);
1701
1702 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1703 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301704 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001705 }
1706
1707 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1708
1709 new_settings(hdev, match.sk);
1710
1711 if (match.sk)
1712 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001713
1714 /* Make sure the controller has a good default for
1715 * advertising data. Restrict the update to when LE
1716 * has actually been enabled. During power on, the
1717 * update in powered_update_hci will take care of it.
1718 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001719 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001720 struct hci_request req;
1721
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001722 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001723 __hci_req_update_adv_data(&req, 0x00);
1724 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001725 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001726 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001727 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301728
1729unlock:
1730 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001731}
1732
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001733static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001734{
1735 struct mgmt_mode *cp = data;
1736 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001737 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001738 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001739 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001740 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001743
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001744 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001745 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1746 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001747
Johan Hedberga7e80f22013-01-09 16:05:19 +02001748 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001749 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001751
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001752 /* Bluetooth single mode LE only controllers or dual-mode
1753 * controllers configured as LE only devices, do not allow
1754 * switching LE off. These have either LE enabled explicitly
1755 * or BR/EDR has been previously switched off.
1756 *
1757 * When trying to enable an already enabled LE, then gracefully
1758 * send a positive response. Trying to disable it however will
1759 * result into rejection.
1760 */
1761 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1762 if (cp->val == 0x01)
1763 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1764
Johan Hedberga69e8372015-03-06 21:08:53 +02001765 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1766 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001767 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001768
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001769 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001770
1771 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001772 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001773
Florian Grandel847818d2015-06-18 03:16:46 +02001774 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001775 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001776
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001777 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001778 bool changed = false;
1779
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001780 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001781 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001782 changed = true;
1783 }
1784
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001785 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001786 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001787 changed = true;
1788 }
1789
Johan Hedberg06199cf2012-02-22 16:37:11 +02001790 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1791 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001792 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001793
1794 if (changed)
1795 err = new_settings(hdev, sk);
1796
Johan Hedberg1de028c2012-02-29 19:55:35 -08001797 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001798 }
1799
Johan Hedberg333ae952015-03-17 13:48:47 +02001800 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1801 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001802 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1803 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001804 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001805 }
1806
1807 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1808 if (!cmd) {
1809 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001810 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001811 }
1812
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001813 hci_req_init(&req, hdev);
1814
Johan Hedberg06199cf2012-02-22 16:37:11 +02001815 memset(&hci_cp, 0, sizeof(hci_cp));
1816
1817 if (val) {
1818 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001819 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001820 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001821 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001822 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001823 }
1824
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001825 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1826 &hci_cp);
1827
1828 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301829 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001830 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001831
Johan Hedberg1de028c2012-02-29 19:55:35 -08001832unlock:
1833 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001834 return err;
1835}
1836
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001837/* This is a helper function to test for pending mgmt commands that can
1838 * cause CoD or EIR HCI commands. We can only allow one such pending
1839 * mgmt command at a time since otherwise we cannot easily track what
1840 * the current values are, will be, and based on that calculate if a new
1841 * HCI command needs to be sent and if yes with what value.
1842 */
1843static bool pending_eir_or_class(struct hci_dev *hdev)
1844{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001845 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001846
1847 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1848 switch (cmd->opcode) {
1849 case MGMT_OP_ADD_UUID:
1850 case MGMT_OP_REMOVE_UUID:
1851 case MGMT_OP_SET_DEV_CLASS:
1852 case MGMT_OP_SET_POWERED:
1853 return true;
1854 }
1855 }
1856
1857 return false;
1858}
1859
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001860static const u8 bluetooth_base_uuid[] = {
1861 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1862 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1863};
1864
1865static u8 get_uuid_size(const u8 *uuid)
1866{
1867 u32 val;
1868
1869 if (memcmp(uuid, bluetooth_base_uuid, 12))
1870 return 128;
1871
1872 val = get_unaligned_le32(&uuid[12]);
1873 if (val > 0xffff)
1874 return 32;
1875
1876 return 16;
1877}
1878
Johan Hedberg92da6092013-03-15 17:06:55 -05001879static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1880{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001881 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001882
1883 hci_dev_lock(hdev);
1884
Johan Hedberg333ae952015-03-17 13:48:47 +02001885 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001886 if (!cmd)
1887 goto unlock;
1888
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001889 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1890 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001891
1892 mgmt_pending_remove(cmd);
1893
1894unlock:
1895 hci_dev_unlock(hdev);
1896}
1897
Marcel Holtmann1904a852015-01-11 13:50:44 -08001898static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001899{
1900 BT_DBG("status 0x%02x", status);
1901
1902 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1903}
1904
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001905static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001906{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001907 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001908 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001909 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001910 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001911 int err;
1912
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001913 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001914
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001915 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001916
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001917 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001918 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1919 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001920 goto failed;
1921 }
1922
Andre Guedes92c4c202012-06-07 19:05:44 -03001923 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001924 if (!uuid) {
1925 err = -ENOMEM;
1926 goto failed;
1927 }
1928
1929 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001930 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001931 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001932
Johan Hedbergde66aa62013-01-27 00:31:27 +02001933 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001934
Johan Hedberg890ea892013-03-15 17:06:52 -05001935 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001936
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001937 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001938 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001939
Johan Hedberg92da6092013-03-15 17:06:55 -05001940 err = hci_req_run(&req, add_uuid_complete);
1941 if (err < 0) {
1942 if (err != -ENODATA)
1943 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001944
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001945 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1946 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001947 goto failed;
1948 }
1949
1950 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001951 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001952 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001953 goto failed;
1954 }
1955
1956 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001957
1958failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001959 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001960 return err;
1961}
1962
Johan Hedberg24b78d02012-02-23 23:24:30 +02001963static bool enable_service_cache(struct hci_dev *hdev)
1964{
1965 if (!hdev_is_powered(hdev))
1966 return false;
1967
Marcel Holtmann238be782015-03-13 02:11:06 -07001968 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001969 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1970 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001971 return true;
1972 }
1973
1974 return false;
1975}
1976
Marcel Holtmann1904a852015-01-11 13:50:44 -08001977static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001978{
1979 BT_DBG("status 0x%02x", status);
1980
1981 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1982}
1983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001985 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001986{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001987 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001988 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001989 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001990 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 -05001991 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001992 int err, found;
1993
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001994 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001996 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001997
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001998 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001999 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2000 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002001 goto unlock;
2002 }
2003
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002005 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002006
Johan Hedberg24b78d02012-02-23 23:24:30 +02002007 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002008 err = mgmt_cmd_complete(sk, hdev->id,
2009 MGMT_OP_REMOVE_UUID,
2010 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002011 goto unlock;
2012 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002013
Johan Hedberg9246a862012-02-23 21:33:16 +02002014 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002015 }
2016
2017 found = 0;
2018
Johan Hedberg056341c2013-01-27 00:31:30 +02002019 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002020 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2021 continue;
2022
2023 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002024 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002025 found++;
2026 }
2027
2028 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002029 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2030 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002031 goto unlock;
2032 }
2033
Johan Hedberg9246a862012-02-23 21:33:16 +02002034update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002035 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002036
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002037 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002038 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002039
Johan Hedberg92da6092013-03-15 17:06:55 -05002040 err = hci_req_run(&req, remove_uuid_complete);
2041 if (err < 0) {
2042 if (err != -ENODATA)
2043 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002044
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002045 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2046 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002047 goto unlock;
2048 }
2049
2050 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002051 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002052 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002053 goto unlock;
2054 }
2055
2056 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002057
2058unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002059 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002060 return err;
2061}
2062
Marcel Holtmann1904a852015-01-11 13:50:44 -08002063static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002064{
2065 BT_DBG("status 0x%02x", status);
2066
2067 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2068}
2069
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002070static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002071 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002072{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002073 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002074 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002075 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002076 int err;
2077
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002079
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002080 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002081 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2082 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002083
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002084 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002085
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002086 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002087 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2088 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002089 goto unlock;
2090 }
2091
2092 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002093 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2094 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002095 goto unlock;
2096 }
2097
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002098 hdev->major_class = cp->major;
2099 hdev->minor_class = cp->minor;
2100
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002101 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002102 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2103 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002104 goto unlock;
2105 }
2106
Johan Hedberg890ea892013-03-15 17:06:52 -05002107 hci_req_init(&req, hdev);
2108
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002109 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002110 hci_dev_unlock(hdev);
2111 cancel_delayed_work_sync(&hdev->service_cache);
2112 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002113 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002114 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002115
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002116 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002117
Johan Hedberg92da6092013-03-15 17:06:55 -05002118 err = hci_req_run(&req, set_class_complete);
2119 if (err < 0) {
2120 if (err != -ENODATA)
2121 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002122
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002123 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2124 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002125 goto unlock;
2126 }
2127
2128 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002129 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002130 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002131 goto unlock;
2132 }
2133
2134 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002135
Johan Hedbergb5235a62012-02-21 14:32:24 +02002136unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002137 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002138 return err;
2139}
2140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002141static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002142 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002143{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002144 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002145 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2146 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002147 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002148 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002149 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002150
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002151 BT_DBG("request for %s", hdev->name);
2152
2153 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002154 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2155 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002156
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002157 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002158 if (key_count > max_key_count) {
2159 BT_ERR("load_link_keys: too big key_count value %u",
2160 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002161 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2162 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002163 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002164
Johan Hedberg86742e12011-11-07 23:13:38 +02002165 expected_len = sizeof(*cp) + key_count *
2166 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002167 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002168 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002169 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002170 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2171 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002172 }
2173
Johan Hedberg4ae14302013-01-20 14:27:13 +02002174 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002175 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2176 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002178 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002179 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002180
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002181 for (i = 0; i < key_count; i++) {
2182 struct mgmt_link_key_info *key = &cp->keys[i];
2183
Marcel Holtmann8e991132014-01-10 02:07:25 -08002184 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002185 return mgmt_cmd_status(sk, hdev->id,
2186 MGMT_OP_LOAD_LINK_KEYS,
2187 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002188 }
2189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002190 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002191
2192 hci_link_keys_clear(hdev);
2193
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002194 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002195 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002196 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002197 changed = hci_dev_test_and_clear_flag(hdev,
2198 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002199
2200 if (changed)
2201 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002203 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002204 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002205
Johan Hedberg58e92932014-06-24 14:00:26 +03002206 /* Always ignore debug keys and require a new pairing if
2207 * the user wants to use them.
2208 */
2209 if (key->type == HCI_LK_DEBUG_COMBINATION)
2210 continue;
2211
Johan Hedberg7652ff62014-06-24 13:15:49 +03002212 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2213 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002214 }
2215
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002216 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002217
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002218 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002219
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002220 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002221}
2222
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002223static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002224 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002225{
2226 struct mgmt_ev_device_unpaired ev;
2227
2228 bacpy(&ev.addr.bdaddr, bdaddr);
2229 ev.addr.type = addr_type;
2230
2231 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002233}
2234
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002235static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002236 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002237{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002238 struct mgmt_cp_unpair_device *cp = data;
2239 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002240 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002241 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002242 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002243 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002244 int err;
2245
Johan Hedberga8a1d192011-11-10 15:54:38 +02002246 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002247 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2248 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002249
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002250 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002251 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2252 MGMT_STATUS_INVALID_PARAMS,
2253 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002254
Johan Hedberg118da702013-01-20 14:27:20 +02002255 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002256 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2257 MGMT_STATUS_INVALID_PARAMS,
2258 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002259
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002260 hci_dev_lock(hdev);
2261
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002262 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002263 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2264 MGMT_STATUS_NOT_POWERED, &rp,
2265 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002266 goto unlock;
2267 }
2268
Johan Hedberge0b2b272014-02-18 17:14:31 +02002269 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002270 /* If disconnection is requested, then look up the
2271 * connection. If the remote device is connected, it
2272 * will be later used to terminate the link.
2273 *
2274 * Setting it to NULL explicitly will cause no
2275 * termination of the link.
2276 */
2277 if (cp->disconnect)
2278 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2279 &cp->addr.bdaddr);
2280 else
2281 conn = NULL;
2282
Johan Hedberg124f6e32012-02-09 13:50:12 +02002283 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002284 if (err < 0) {
2285 err = mgmt_cmd_complete(sk, hdev->id,
2286 MGMT_OP_UNPAIR_DEVICE,
2287 MGMT_STATUS_NOT_PAIRED, &rp,
2288 sizeof(rp));
2289 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002290 }
2291
Johan Hedbergec182f02015-10-21 18:03:03 +03002292 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002293 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002294
Johan Hedbergec182f02015-10-21 18:03:03 +03002295 /* LE address type */
2296 addr_type = le_addr_type(cp->addr.type);
2297
2298 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2299
2300 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002301 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002302 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2303 MGMT_STATUS_NOT_PAIRED, &rp,
2304 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002305 goto unlock;
2306 }
2307
Johan Hedbergec182f02015-10-21 18:03:03 +03002308 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2309 if (!conn) {
2310 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2311 goto done;
2312 }
2313
Johan Hedbergc81d5552015-10-22 09:38:35 +03002314 /* Abort any ongoing SMP pairing */
2315 smp_cancel_pairing(conn);
2316
Johan Hedbergec182f02015-10-21 18:03:03 +03002317 /* Defer clearing up the connection parameters until closing to
2318 * give a chance of keeping them if a repairing happens.
2319 */
2320 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2321
Johan Hedbergfc643612015-10-22 09:38:31 +03002322 /* Disable auto-connection parameters if present */
2323 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2324 if (params) {
2325 if (params->explicit_connect)
2326 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2327 else
2328 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2329 }
2330
Johan Hedbergec182f02015-10-21 18:03:03 +03002331 /* If disconnection is not requested, then clear the connection
2332 * variable so that the link is not terminated.
2333 */
2334 if (!cp->disconnect)
2335 conn = NULL;
2336
2337done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002338 /* If the connection variable is set, then termination of the
2339 * link is requested.
2340 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002341 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002342 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2343 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002344 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002345 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002346 }
2347
Johan Hedberg124f6e32012-02-09 13:50:12 +02002348 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002349 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002350 if (!cmd) {
2351 err = -ENOMEM;
2352 goto unlock;
2353 }
2354
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002355 cmd->cmd_complete = addr_cmd_complete;
2356
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002357 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002358 if (err < 0)
2359 mgmt_pending_remove(cmd);
2360
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002361unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002362 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002363 return err;
2364}
2365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002366static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002368{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002369 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002370 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002371 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002373 int err;
2374
2375 BT_DBG("");
2376
Johan Hedberg06a63b12013-01-20 14:27:21 +02002377 memset(&rp, 0, sizeof(rp));
2378 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2379 rp.addr.type = cp->addr.type;
2380
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002381 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002382 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2383 MGMT_STATUS_INVALID_PARAMS,
2384 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002385
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002386 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002387
2388 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002389 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2390 MGMT_STATUS_NOT_POWERED, &rp,
2391 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002392 goto failed;
2393 }
2394
Johan Hedberg333ae952015-03-17 13:48:47 +02002395 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002396 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2397 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002398 goto failed;
2399 }
2400
Andre Guedes591f47f2012-04-24 21:02:49 -03002401 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002402 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2403 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002404 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002405 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2406 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002407
Vishal Agarwalf9607272012-06-13 05:32:43 +05302408 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002409 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2410 MGMT_STATUS_NOT_CONNECTED, &rp,
2411 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002412 goto failed;
2413 }
2414
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002415 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002416 if (!cmd) {
2417 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002419 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002420
Johan Hedbergf5818c22014-12-05 13:36:02 +02002421 cmd->cmd_complete = generic_cmd_complete;
2422
Johan Hedberge3f2f922014-08-18 20:33:33 +03002423 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002424 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002425 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002426
2427failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002428 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002429 return err;
2430}
2431
Andre Guedes57c14772012-04-24 21:02:50 -03002432static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002433{
2434 switch (link_type) {
2435 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002436 switch (addr_type) {
2437 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002438 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002439
Johan Hedberg48264f02011-11-09 13:58:58 +02002440 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002441 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002442 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002443 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002444
Johan Hedberg4c659c32011-11-07 23:13:39 +02002445 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002446 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002447 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002448 }
2449}
2450
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002451static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2452 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002453{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002454 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002455 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002456 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002457 int err;
2458 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002459
2460 BT_DBG("");
2461
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002463
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002464 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002465 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2466 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002467 goto unlock;
2468 }
2469
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002470 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002471 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2472 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002473 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002474 }
2475
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002476 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002477 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002478 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002479 err = -ENOMEM;
2480 goto unlock;
2481 }
2482
Johan Hedberg2784eb42011-01-21 13:56:35 +02002483 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002484 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002485 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2486 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002487 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002488 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002489 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002490 continue;
2491 i++;
2492 }
2493
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002494 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002495
Johan Hedberg4c659c32011-11-07 23:13:39 +02002496 /* Recalculate length in case of filtered SCO connections, etc */
2497 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002498
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002499 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2500 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002501
Johan Hedberga38528f2011-01-22 06:46:43 +02002502 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002503
2504unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002505 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002506 return err;
2507}
2508
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002509static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002510 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002511{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002512 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002513 int err;
2514
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002515 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002517 if (!cmd)
2518 return -ENOMEM;
2519
Johan Hedbergd8457692012-02-17 14:24:57 +02002520 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002521 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002522 if (err < 0)
2523 mgmt_pending_remove(cmd);
2524
2525 return err;
2526}
2527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002528static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002529 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002531 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002532 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002534 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002535 int err;
2536
2537 BT_DBG("");
2538
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002539 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002540
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002541 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002542 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2543 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002544 goto failed;
2545 }
2546
Johan Hedbergd8457692012-02-17 14:24:57 +02002547 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002548 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002549 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2550 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002551 goto failed;
2552 }
2553
2554 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002555 struct mgmt_cp_pin_code_neg_reply ncp;
2556
2557 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002558
2559 BT_ERR("PIN code is not 16 bytes long");
2560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002561 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002562 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002563 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2564 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002565
2566 goto failed;
2567 }
2568
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002569 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002570 if (!cmd) {
2571 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002572 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002573 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002574
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002575 cmd->cmd_complete = addr_cmd_complete;
2576
Johan Hedbergd8457692012-02-17 14:24:57 +02002577 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002578 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002579 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002580
2581 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2582 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002583 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002584
2585failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002586 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002587 return err;
2588}
2589
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2591 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002592{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002593 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002594
2595 BT_DBG("");
2596
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002597 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002598 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2599 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002602
2603 hdev->io_capability = cp->io_capability;
2604
2605 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002606 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002607
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002608 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002609
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002610 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2611 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002612}
2613
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002614static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002615{
2616 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002617 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002618
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002619 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002620 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2621 continue;
2622
Johan Hedberge9a416b2011-02-19 12:05:56 -03002623 if (cmd->user_data != conn)
2624 continue;
2625
2626 return cmd;
2627 }
2628
2629 return NULL;
2630}
2631
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002632static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002633{
2634 struct mgmt_rp_pair_device rp;
2635 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002636 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002637
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002638 bacpy(&rp.addr.bdaddr, &conn->dst);
2639 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002640
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002641 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2642 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002643
2644 /* So we don't get further callbacks for this connection */
2645 conn->connect_cfm_cb = NULL;
2646 conn->security_cfm_cb = NULL;
2647 conn->disconn_cfm_cb = NULL;
2648
David Herrmann76a68ba2013-04-06 20:28:37 +02002649 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002650
2651 /* The device is paired so there is no need to remove
2652 * its connection parameters anymore.
2653 */
2654 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002655
2656 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002657
2658 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002659}
2660
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002661void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2662{
2663 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002664 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002665
2666 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002667 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002668 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002669 mgmt_pending_remove(cmd);
2670 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002671}
2672
Johan Hedberge9a416b2011-02-19 12:05:56 -03002673static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2674{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002675 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002676
2677 BT_DBG("status %u", status);
2678
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002679 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002680 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002681 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002682 return;
2683 }
2684
2685 cmd->cmd_complete(cmd, mgmt_status(status));
2686 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002687}
2688
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002689static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302690{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002691 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302692
2693 BT_DBG("status %u", status);
2694
2695 if (!status)
2696 return;
2697
2698 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002699 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302700 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002701 return;
2702 }
2703
2704 cmd->cmd_complete(cmd, mgmt_status(status));
2705 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302706}
2707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002708static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002709 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002710{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002711 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002712 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002713 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002714 u8 sec_level, auth_type;
2715 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002716 int err;
2717
2718 BT_DBG("");
2719
Szymon Jancf950a30e2013-01-18 12:48:07 +01002720 memset(&rp, 0, sizeof(rp));
2721 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2722 rp.addr.type = cp->addr.type;
2723
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002724 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002725 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2726 MGMT_STATUS_INVALID_PARAMS,
2727 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002728
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002729 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002730 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2731 MGMT_STATUS_INVALID_PARAMS,
2732 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002733
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002734 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002735
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002736 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002737 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2738 MGMT_STATUS_NOT_POWERED, &rp,
2739 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002740 goto unlock;
2741 }
2742
Johan Hedberg55e76b32015-03-10 22:34:40 +02002743 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2744 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2745 MGMT_STATUS_ALREADY_PAIRED, &rp,
2746 sizeof(rp));
2747 goto unlock;
2748 }
2749
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002750 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002751 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002752
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002753 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002754 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2755 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002756 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002757 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002758 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002759
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002760 /* When pairing a new device, it is expected to remember
2761 * this device for future connections. Adding the connection
2762 * parameter information ahead of time allows tracking
2763 * of the slave preferred values and will speed up any
2764 * further connection establishment.
2765 *
2766 * If connection parameters already exist, then they
2767 * will be kept and this function does nothing.
2768 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002769 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2770
2771 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2772 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002773
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002774 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2775 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002776 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002777 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002778
Ville Tervo30e76272011-02-22 16:10:53 -03002779 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002780 int status;
2781
2782 if (PTR_ERR(conn) == -EBUSY)
2783 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002784 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2785 status = MGMT_STATUS_NOT_SUPPORTED;
2786 else if (PTR_ERR(conn) == -ECONNREFUSED)
2787 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002788 else
2789 status = MGMT_STATUS_CONNECT_FAILED;
2790
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002791 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2792 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793 goto unlock;
2794 }
2795
2796 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002797 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002798 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2799 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002800 goto unlock;
2801 }
2802
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002803 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002804 if (!cmd) {
2805 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002806 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002807 goto unlock;
2808 }
2809
Johan Hedberg04ab2742014-12-05 13:36:04 +02002810 cmd->cmd_complete = pairing_complete;
2811
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002812 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002813 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002814 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002815 conn->security_cfm_cb = pairing_complete_cb;
2816 conn->disconn_cfm_cb = pairing_complete_cb;
2817 } else {
2818 conn->connect_cfm_cb = le_pairing_complete_cb;
2819 conn->security_cfm_cb = le_pairing_complete_cb;
2820 conn->disconn_cfm_cb = le_pairing_complete_cb;
2821 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002822
Johan Hedberge9a416b2011-02-19 12:05:56 -03002823 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002824 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002825
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002826 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002827 hci_conn_security(conn, sec_level, auth_type, true)) {
2828 cmd->cmd_complete(cmd, 0);
2829 mgmt_pending_remove(cmd);
2830 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002831
2832 err = 0;
2833
2834unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002835 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002836 return err;
2837}
2838
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002839static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2840 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002841{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002842 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002843 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002844 struct hci_conn *conn;
2845 int err;
2846
2847 BT_DBG("");
2848
Johan Hedberg28424702012-02-02 04:02:29 +02002849 hci_dev_lock(hdev);
2850
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002851 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002852 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2853 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002854 goto unlock;
2855 }
2856
Johan Hedberg333ae952015-03-17 13:48:47 +02002857 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002858 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002859 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2860 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002861 goto unlock;
2862 }
2863
2864 conn = cmd->user_data;
2865
2866 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002867 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002869 goto unlock;
2870 }
2871
Johan Hedberga511b352014-12-11 21:45:45 +02002872 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2873 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002874
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002875 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2876 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002877unlock:
2878 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002879 return err;
2880}
2881
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002882static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002883 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002884 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002885{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002886 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002887 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002888 int err;
2889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002890 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002891
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002892 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002893 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2894 MGMT_STATUS_NOT_POWERED, addr,
2895 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002896 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002897 }
2898
Johan Hedberg1707c602013-03-15 17:07:15 -05002899 if (addr->type == BDADDR_BREDR)
2900 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002901 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002902 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2903 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002904
Johan Hedberg272d90d2012-02-09 15:26:12 +02002905 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002906 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2907 MGMT_STATUS_NOT_CONNECTED, addr,
2908 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002909 goto done;
2910 }
2911
Johan Hedberg1707c602013-03-15 17:07:15 -05002912 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002913 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002914 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002915 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2916 MGMT_STATUS_SUCCESS, addr,
2917 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002918 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002919 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2920 MGMT_STATUS_FAILED, addr,
2921 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002922
Brian Gix47c15e22011-11-16 13:53:14 -08002923 goto done;
2924 }
2925
Johan Hedberg1707c602013-03-15 17:07:15 -05002926 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002927 if (!cmd) {
2928 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002929 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002930 }
2931
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002932 cmd->cmd_complete = addr_cmd_complete;
2933
Brian Gix0df4c182011-11-16 13:53:13 -08002934 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002935 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2936 struct hci_cp_user_passkey_reply cp;
2937
Johan Hedberg1707c602013-03-15 17:07:15 -05002938 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002939 cp.passkey = passkey;
2940 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2941 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002942 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2943 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002944
Johan Hedberga664b5b2011-02-19 12:06:02 -03002945 if (err < 0)
2946 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002947
Brian Gix0df4c182011-11-16 13:53:13 -08002948done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002949 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002950 return err;
2951}
2952
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302953static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2954 void *data, u16 len)
2955{
2956 struct mgmt_cp_pin_code_neg_reply *cp = data;
2957
2958 BT_DBG("");
2959
Johan Hedberg1707c602013-03-15 17:07:15 -05002960 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302961 MGMT_OP_PIN_CODE_NEG_REPLY,
2962 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2963}
2964
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002965static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2966 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002967{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002969
2970 BT_DBG("");
2971
2972 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002973 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2974 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002975
Johan Hedberg1707c602013-03-15 17:07:15 -05002976 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002977 MGMT_OP_USER_CONFIRM_REPLY,
2978 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002979}
2980
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002981static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002982 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002983{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002984 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002985
2986 BT_DBG("");
2987
Johan Hedberg1707c602013-03-15 17:07:15 -05002988 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002989 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2990 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002991}
2992
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002993static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2994 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002995{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002996 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002997
2998 BT_DBG("");
2999
Johan Hedberg1707c602013-03-15 17:07:15 -05003000 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003001 MGMT_OP_USER_PASSKEY_REPLY,
3002 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003003}
3004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003005static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003006 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003007{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003008 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003009
3010 BT_DBG("");
3011
Johan Hedberg1707c602013-03-15 17:07:15 -05003012 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3014 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003015}
3016
Marcel Holtmann1904a852015-01-11 13:50:44 -08003017static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003018{
3019 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003020 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003021
3022 BT_DBG("status 0x%02x", status);
3023
3024 hci_dev_lock(hdev);
3025
Johan Hedberg333ae952015-03-17 13:48:47 +02003026 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003027 if (!cmd)
3028 goto unlock;
3029
3030 cp = cmd->param;
3031
3032 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003033 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3034 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003035 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003036 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3037 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003038
3039 mgmt_pending_remove(cmd);
3040
3041unlock:
3042 hci_dev_unlock(hdev);
3043}
3044
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003045static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003046 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003047{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003048 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003049 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003050 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003051 int err;
3052
3053 BT_DBG("");
3054
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003055 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003056
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003057 /* If the old values are the same as the new ones just return a
3058 * direct command complete event.
3059 */
3060 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3061 !memcmp(hdev->short_name, cp->short_name,
3062 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003063 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3064 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003065 goto failed;
3066 }
3067
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003068 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003069
Johan Hedbergb5235a62012-02-21 14:32:24 +02003070 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003071 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003072
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003073 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3074 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003075 if (err < 0)
3076 goto failed;
3077
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003078 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3079 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003080 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003081
Johan Hedbergb5235a62012-02-21 14:32:24 +02003082 goto failed;
3083 }
3084
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003085 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003086 if (!cmd) {
3087 err = -ENOMEM;
3088 goto failed;
3089 }
3090
Johan Hedberg13928972013-03-15 17:07:00 -05003091 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3092
Johan Hedberg890ea892013-03-15 17:06:52 -05003093 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003094
3095 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003096 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003097 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003098 }
3099
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003100 /* The name is stored in the scan response data and so
3101 * no need to udpate the advertising data here.
3102 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003103 if (lmp_le_capable(hdev))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003104 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003105
Johan Hedberg13928972013-03-15 17:07:00 -05003106 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003107 if (err < 0)
3108 mgmt_pending_remove(cmd);
3109
3110failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003111 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003112 return err;
3113}
3114
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003115static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3116 u16 opcode, struct sk_buff *skb)
3117{
3118 struct mgmt_rp_read_local_oob_data mgmt_rp;
3119 size_t rp_size = sizeof(mgmt_rp);
3120 struct mgmt_pending_cmd *cmd;
3121
3122 BT_DBG("%s status %u", hdev->name, status);
3123
3124 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3125 if (!cmd)
3126 return;
3127
3128 if (status || !skb) {
3129 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3130 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3131 goto remove;
3132 }
3133
3134 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3135
3136 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3137 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3138
3139 if (skb->len < sizeof(*rp)) {
3140 mgmt_cmd_status(cmd->sk, hdev->id,
3141 MGMT_OP_READ_LOCAL_OOB_DATA,
3142 MGMT_STATUS_FAILED);
3143 goto remove;
3144 }
3145
3146 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3147 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3148
3149 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3150 } else {
3151 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3152
3153 if (skb->len < sizeof(*rp)) {
3154 mgmt_cmd_status(cmd->sk, hdev->id,
3155 MGMT_OP_READ_LOCAL_OOB_DATA,
3156 MGMT_STATUS_FAILED);
3157 goto remove;
3158 }
3159
3160 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3161 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3162
3163 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3164 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3165 }
3166
3167 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3168 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3169
3170remove:
3171 mgmt_pending_remove(cmd);
3172}
3173
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003174static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003176{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003177 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003178 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003179 int err;
3180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003181 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003182
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003183 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003184
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003185 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003186 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3187 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003188 goto unlock;
3189 }
3190
Andre Guedes9a1a1992012-07-24 15:03:48 -03003191 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003192 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3193 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003194 goto unlock;
3195 }
3196
Johan Hedberg333ae952015-03-17 13:48:47 +02003197 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003198 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3199 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003200 goto unlock;
3201 }
3202
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003203 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003204 if (!cmd) {
3205 err = -ENOMEM;
3206 goto unlock;
3207 }
3208
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003209 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003210
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003211 if (bredr_sc_enabled(hdev))
3212 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3213 else
3214 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3215
3216 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003217 if (err < 0)
3218 mgmt_pending_remove(cmd);
3219
3220unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003221 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003222 return err;
3223}
3224
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003225static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003226 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003227{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003228 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003229 int err;
3230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003231 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003232
Johan Hedberg5d57e792015-01-23 10:10:38 +02003233 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003234 return mgmt_cmd_complete(sk, hdev->id,
3235 MGMT_OP_ADD_REMOTE_OOB_DATA,
3236 MGMT_STATUS_INVALID_PARAMS,
3237 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003239 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003240
Marcel Holtmannec109112014-01-10 02:07:30 -08003241 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3242 struct mgmt_cp_add_remote_oob_data *cp = data;
3243 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003244
Johan Hedbergc19a4952014-11-17 20:52:19 +02003245 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003246 err = mgmt_cmd_complete(sk, hdev->id,
3247 MGMT_OP_ADD_REMOTE_OOB_DATA,
3248 MGMT_STATUS_INVALID_PARAMS,
3249 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003250 goto unlock;
3251 }
3252
Marcel Holtmannec109112014-01-10 02:07:30 -08003253 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003254 cp->addr.type, cp->hash,
3255 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003256 if (err < 0)
3257 status = MGMT_STATUS_FAILED;
3258 else
3259 status = MGMT_STATUS_SUCCESS;
3260
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003261 err = mgmt_cmd_complete(sk, hdev->id,
3262 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3263 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003264 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3265 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003266 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003267 u8 status;
3268
Johan Hedberg86df9202014-10-26 20:52:27 +01003269 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003270 /* Enforce zero-valued 192-bit parameters as
3271 * long as legacy SMP OOB isn't implemented.
3272 */
3273 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3274 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003275 err = mgmt_cmd_complete(sk, hdev->id,
3276 MGMT_OP_ADD_REMOTE_OOB_DATA,
3277 MGMT_STATUS_INVALID_PARAMS,
3278 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003279 goto unlock;
3280 }
3281
Johan Hedberg86df9202014-10-26 20:52:27 +01003282 rand192 = NULL;
3283 hash192 = NULL;
3284 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003285 /* In case one of the P-192 values is set to zero,
3286 * then just disable OOB data for P-192.
3287 */
3288 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3289 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3290 rand192 = NULL;
3291 hash192 = NULL;
3292 } else {
3293 rand192 = cp->rand192;
3294 hash192 = cp->hash192;
3295 }
3296 }
3297
3298 /* In case one of the P-256 values is set to zero, then just
3299 * disable OOB data for P-256.
3300 */
3301 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3302 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3303 rand256 = NULL;
3304 hash256 = NULL;
3305 } else {
3306 rand256 = cp->rand256;
3307 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003308 }
3309
Johan Hedberg81328d52014-10-26 20:33:47 +01003310 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003311 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003312 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003313 if (err < 0)
3314 status = MGMT_STATUS_FAILED;
3315 else
3316 status = MGMT_STATUS_SUCCESS;
3317
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003318 err = mgmt_cmd_complete(sk, hdev->id,
3319 MGMT_OP_ADD_REMOTE_OOB_DATA,
3320 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003321 } else {
3322 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003323 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3324 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003325 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003326
Johan Hedbergc19a4952014-11-17 20:52:19 +02003327unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003328 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003329 return err;
3330}
3331
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003332static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003333 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003334{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003335 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003336 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003337 int err;
3338
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003339 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003340
Johan Hedbergc19a4952014-11-17 20:52:19 +02003341 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003342 return mgmt_cmd_complete(sk, hdev->id,
3343 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3344 MGMT_STATUS_INVALID_PARAMS,
3345 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003346
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003347 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003348
Johan Hedbergeedbd582014-11-15 09:34:23 +02003349 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3350 hci_remote_oob_data_clear(hdev);
3351 status = MGMT_STATUS_SUCCESS;
3352 goto done;
3353 }
3354
Johan Hedberg6928a922014-10-26 20:46:09 +01003355 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003356 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003357 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003358 else
Szymon Janca6785be2012-12-13 15:11:21 +01003359 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003360
Johan Hedbergeedbd582014-11-15 09:34:23 +02003361done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003362 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3363 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003364
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003365 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003366 return err;
3367}
3368
Johan Hedberge68f0722015-11-11 08:30:30 +02003369void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003370{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003371 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003372
Andre Guedes7c307722013-04-30 15:29:28 -03003373 BT_DBG("status %d", status);
3374
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003375 hci_dev_lock(hdev);
3376
Johan Hedberg333ae952015-03-17 13:48:47 +02003377 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003378 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003379 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003380
Johan Hedberg78b781c2016-01-05 13:19:32 +02003381 if (!cmd)
3382 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3383
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003384 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003385 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003386 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003387 }
3388
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003389 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003390}
3391
Johan Hedberg591752a2015-11-11 08:11:24 +02003392static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3393 uint8_t *mgmt_status)
3394{
3395 switch (type) {
3396 case DISCOV_TYPE_LE:
3397 *mgmt_status = mgmt_le_support(hdev);
3398 if (*mgmt_status)
3399 return false;
3400 break;
3401 case DISCOV_TYPE_INTERLEAVED:
3402 *mgmt_status = mgmt_le_support(hdev);
3403 if (*mgmt_status)
3404 return false;
3405 /* Intentional fall-through */
3406 case DISCOV_TYPE_BREDR:
3407 *mgmt_status = mgmt_bredr_support(hdev);
3408 if (*mgmt_status)
3409 return false;
3410 break;
3411 default:
3412 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3413 return false;
3414 }
3415
3416 return true;
3417}
3418
Johan Hedberg78b781c2016-01-05 13:19:32 +02003419static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3420 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003421{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003422 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003423 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003424 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003425 int err;
3426
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003427 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003428
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003429 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003430
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003431 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003432 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003433 MGMT_STATUS_NOT_POWERED,
3434 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003435 goto failed;
3436 }
3437
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003438 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003439 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003440 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3441 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003442 goto failed;
3443 }
3444
Johan Hedberg591752a2015-11-11 08:11:24 +02003445 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003446 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3447 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003448 goto failed;
3449 }
3450
Marcel Holtmann22078802014-12-05 11:45:22 +01003451 /* Clear the discovery filter first to free any previously
3452 * allocated memory for the UUID list.
3453 */
3454 hci_discovery_filter_clear(hdev);
3455
Andre Guedes4aab14e2012-02-17 20:39:36 -03003456 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003457 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003458 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3459 hdev->discovery.limited = true;
3460 else
3461 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003462
Johan Hedberg78b781c2016-01-05 13:19:32 +02003463 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003464 if (!cmd) {
3465 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003466 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003467 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003468
Johan Hedberge68f0722015-11-11 08:30:30 +02003469 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003470
3471 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003472 queue_work(hdev->req_workqueue, &hdev->discov_update);
3473 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003474
3475failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003476 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003477 return err;
3478}
3479
Johan Hedberg78b781c2016-01-05 13:19:32 +02003480static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3481 void *data, u16 len)
3482{
3483 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3484 data, len);
3485}
3486
3487static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3488 void *data, u16 len)
3489{
3490 return start_discovery_internal(sk, hdev,
3491 MGMT_OP_START_LIMITED_DISCOVERY,
3492 data, len);
3493}
3494
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003495static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3496 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003497{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003498 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3499 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003500}
3501
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003502static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3503 void *data, u16 len)
3504{
3505 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003506 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003507 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3508 u16 uuid_count, expected_len;
3509 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003510 int err;
3511
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003512 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003513
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003514 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003515
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003516 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003517 err = mgmt_cmd_complete(sk, hdev->id,
3518 MGMT_OP_START_SERVICE_DISCOVERY,
3519 MGMT_STATUS_NOT_POWERED,
3520 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003521 goto failed;
3522 }
3523
3524 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003525 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003526 err = mgmt_cmd_complete(sk, hdev->id,
3527 MGMT_OP_START_SERVICE_DISCOVERY,
3528 MGMT_STATUS_BUSY, &cp->type,
3529 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003530 goto failed;
3531 }
3532
3533 uuid_count = __le16_to_cpu(cp->uuid_count);
3534 if (uuid_count > max_uuid_count) {
3535 BT_ERR("service_discovery: too big uuid_count value %u",
3536 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003537 err = mgmt_cmd_complete(sk, hdev->id,
3538 MGMT_OP_START_SERVICE_DISCOVERY,
3539 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3540 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003541 goto failed;
3542 }
3543
3544 expected_len = sizeof(*cp) + uuid_count * 16;
3545 if (expected_len != len) {
3546 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3547 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003548 err = mgmt_cmd_complete(sk, hdev->id,
3549 MGMT_OP_START_SERVICE_DISCOVERY,
3550 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3551 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003552 goto failed;
3553 }
3554
Johan Hedberg591752a2015-11-11 08:11:24 +02003555 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3556 err = mgmt_cmd_complete(sk, hdev->id,
3557 MGMT_OP_START_SERVICE_DISCOVERY,
3558 status, &cp->type, sizeof(cp->type));
3559 goto failed;
3560 }
3561
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003562 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003563 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003564 if (!cmd) {
3565 err = -ENOMEM;
3566 goto failed;
3567 }
3568
Johan Hedberg2922a942014-12-05 13:36:06 +02003569 cmd->cmd_complete = service_discovery_cmd_complete;
3570
Marcel Holtmann22078802014-12-05 11:45:22 +01003571 /* Clear the discovery filter first to free any previously
3572 * allocated memory for the UUID list.
3573 */
3574 hci_discovery_filter_clear(hdev);
3575
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003576 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003577 hdev->discovery.type = cp->type;
3578 hdev->discovery.rssi = cp->rssi;
3579 hdev->discovery.uuid_count = uuid_count;
3580
3581 if (uuid_count > 0) {
3582 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3583 GFP_KERNEL);
3584 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003585 err = mgmt_cmd_complete(sk, hdev->id,
3586 MGMT_OP_START_SERVICE_DISCOVERY,
3587 MGMT_STATUS_FAILED,
3588 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003589 mgmt_pending_remove(cmd);
3590 goto failed;
3591 }
3592 }
3593
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003594 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003595 queue_work(hdev->req_workqueue, &hdev->discov_update);
3596 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003597
3598failed:
3599 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003600 return err;
3601}
3602
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003603void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003604{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003605 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003606
Andre Guedes0e05bba2013-04-30 15:29:33 -03003607 BT_DBG("status %d", status);
3608
3609 hci_dev_lock(hdev);
3610
Johan Hedberg333ae952015-03-17 13:48:47 +02003611 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003612 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003613 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003614 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003615 }
3616
Andre Guedes0e05bba2013-04-30 15:29:33 -03003617 hci_dev_unlock(hdev);
3618}
3619
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003620static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003621 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003622{
Johan Hedbergd9306502012-02-20 23:25:18 +02003623 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003624 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003625 int err;
3626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003627 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003629 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003630
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003631 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003632 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3633 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3634 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003635 goto unlock;
3636 }
3637
3638 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003639 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3640 MGMT_STATUS_INVALID_PARAMS,
3641 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003642 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003643 }
3644
Johan Hedberg2922a942014-12-05 13:36:06 +02003645 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003646 if (!cmd) {
3647 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003648 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003649 }
3650
Johan Hedberg2922a942014-12-05 13:36:06 +02003651 cmd->cmd_complete = generic_cmd_complete;
3652
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003653 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3654 queue_work(hdev->req_workqueue, &hdev->discov_update);
3655 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003656
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003657unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003658 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003659 return err;
3660}
3661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003662static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003663 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003664{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003665 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003666 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003667 int err;
3668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003669 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003670
Johan Hedberg561aafb2012-01-04 13:31:59 +02003671 hci_dev_lock(hdev);
3672
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003673 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003674 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3675 MGMT_STATUS_FAILED, &cp->addr,
3676 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003677 goto failed;
3678 }
3679
Johan Hedberga198e7b2012-02-17 14:27:06 +02003680 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003681 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003682 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3683 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3684 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003685 goto failed;
3686 }
3687
3688 if (cp->name_known) {
3689 e->name_state = NAME_KNOWN;
3690 list_del(&e->list);
3691 } else {
3692 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003693 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003694 }
3695
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003696 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3697 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003698
3699failed:
3700 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003701 return err;
3702}
3703
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003704static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003705 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003706{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003707 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003708 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003709 int err;
3710
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003711 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003712
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003713 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003714 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3715 MGMT_STATUS_INVALID_PARAMS,
3716 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003717
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003718 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003719
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003720 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3721 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003722 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003723 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003724 goto done;
3725 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003726
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003727 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3728 sk);
3729 status = MGMT_STATUS_SUCCESS;
3730
3731done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003732 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3733 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003734
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003735 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003736
3737 return err;
3738}
3739
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003740static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003741 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003742{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003743 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003744 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003745 int err;
3746
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003747 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003748
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003749 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003750 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3751 MGMT_STATUS_INVALID_PARAMS,
3752 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003753
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003754 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003755
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003756 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3757 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003758 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003759 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003760 goto done;
3761 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003762
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003763 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3764 sk);
3765 status = MGMT_STATUS_SUCCESS;
3766
3767done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003768 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3769 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003770
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003771 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003772
3773 return err;
3774}
3775
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003776static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3777 u16 len)
3778{
3779 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003780 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003781 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003782 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003783
3784 BT_DBG("%s", hdev->name);
3785
Szymon Jancc72d4b82012-03-16 16:02:57 +01003786 source = __le16_to_cpu(cp->source);
3787
3788 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003789 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3790 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003791
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003792 hci_dev_lock(hdev);
3793
Szymon Jancc72d4b82012-03-16 16:02:57 +01003794 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003795 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3796 hdev->devid_product = __le16_to_cpu(cp->product);
3797 hdev->devid_version = __le16_to_cpu(cp->version);
3798
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003799 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3800 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003801
Johan Hedberg890ea892013-03-15 17:06:52 -05003802 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003803 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003804 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003805
3806 hci_dev_unlock(hdev);
3807
3808 return err;
3809}
3810
Arman Uguray24b4f382015-03-23 15:57:12 -07003811static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3812 u16 opcode)
3813{
3814 BT_DBG("status %d", status);
3815}
3816
Marcel Holtmann1904a852015-01-11 13:50:44 -08003817static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3818 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003819{
3820 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003821 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003822 u8 instance;
3823 struct adv_info *adv_instance;
3824 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003825
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303826 hci_dev_lock(hdev);
3827
Johan Hedberg4375f102013-09-25 13:26:10 +03003828 if (status) {
3829 u8 mgmt_err = mgmt_status(status);
3830
3831 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3832 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303833 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003834 }
3835
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003836 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003837 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003838 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003839 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003840
Johan Hedberg4375f102013-09-25 13:26:10 +03003841 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3842 &match);
3843
3844 new_settings(hdev, match.sk);
3845
3846 if (match.sk)
3847 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303848
Arman Uguray24b4f382015-03-23 15:57:12 -07003849 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003850 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003851 */
3852 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003853 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003854 goto unlock;
3855
Florian Grandel7816b822015-06-18 03:16:45 +02003856 instance = hdev->cur_adv_instance;
3857 if (!instance) {
3858 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3859 struct adv_info, list);
3860 if (!adv_instance)
3861 goto unlock;
3862
3863 instance = adv_instance->instance;
3864 }
3865
Arman Uguray24b4f382015-03-23 15:57:12 -07003866 hci_req_init(&req, hdev);
3867
Johan Hedbergf2252572015-11-18 12:49:20 +02003868 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003869
Florian Grandel7816b822015-06-18 03:16:45 +02003870 if (!err)
3871 err = hci_req_run(&req, enable_advertising_instance);
3872
3873 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003874 BT_ERR("Failed to re-configure advertising");
3875
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303876unlock:
3877 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003878}
3879
Marcel Holtmann21b51872013-10-10 09:47:53 -07003880static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3881 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003882{
3883 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003884 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003885 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003886 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003887 int err;
3888
3889 BT_DBG("request for %s", hdev->name);
3890
Johan Hedberge6fe7982013-10-02 15:45:22 +03003891 status = mgmt_le_support(hdev);
3892 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003893 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3894 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003895
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003896 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003897 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3898 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003899
3900 hci_dev_lock(hdev);
3901
3902 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003903
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003904 /* The following conditions are ones which mean that we should
3905 * not do any HCI communication but directly send a mgmt
3906 * response to user space (after toggling the flag if
3907 * necessary).
3908 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003909 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003910 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3911 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003912 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003913 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003914 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003915 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003916
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003917 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003918 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07003919 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003920 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003921 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003922 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003923 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003924 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003925 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003926 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003927 }
3928
3929 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3930 if (err < 0)
3931 goto unlock;
3932
3933 if (changed)
3934 err = new_settings(hdev, sk);
3935
3936 goto unlock;
3937 }
3938
Johan Hedberg333ae952015-03-17 13:48:47 +02003939 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3940 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003941 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3942 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03003943 goto unlock;
3944 }
3945
3946 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3947 if (!cmd) {
3948 err = -ENOMEM;
3949 goto unlock;
3950 }
3951
3952 hci_req_init(&req, hdev);
3953
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003954 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003955 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003956 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003957 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003958
Florian Grandel7816b822015-06-18 03:16:45 +02003959 cancel_adv_timeout(hdev);
3960
Arman Uguray24b4f382015-03-23 15:57:12 -07003961 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02003962 /* Switch to instance "0" for the Set Advertising setting.
3963 * We cannot use update_[adv|scan_rsp]_data() here as the
3964 * HCI_ADVERTISING flag is not yet set.
3965 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02003966 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02003967 __hci_req_update_adv_data(&req, 0x00);
3968 __hci_req_update_scan_rsp_data(&req, 0x00);
3969 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003970 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02003971 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003972 }
Johan Hedberg4375f102013-09-25 13:26:10 +03003973
3974 err = hci_req_run(&req, set_advertising_complete);
3975 if (err < 0)
3976 mgmt_pending_remove(cmd);
3977
3978unlock:
3979 hci_dev_unlock(hdev);
3980 return err;
3981}
3982
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003983static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3984 void *data, u16 len)
3985{
3986 struct mgmt_cp_set_static_address *cp = data;
3987 int err;
3988
3989 BT_DBG("%s", hdev->name);
3990
Marcel Holtmann62af4442013-10-02 22:10:32 -07003991 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003992 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3993 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003994
3995 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003996 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3997 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003998
3999 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4000 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004001 return mgmt_cmd_status(sk, hdev->id,
4002 MGMT_OP_SET_STATIC_ADDRESS,
4003 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004004
4005 /* Two most significant bits shall be set */
4006 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004007 return mgmt_cmd_status(sk, hdev->id,
4008 MGMT_OP_SET_STATIC_ADDRESS,
4009 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004010 }
4011
4012 hci_dev_lock(hdev);
4013
4014 bacpy(&hdev->static_addr, &cp->bdaddr);
4015
Marcel Holtmann93690c22015-03-06 10:11:21 -08004016 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4017 if (err < 0)
4018 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004019
Marcel Holtmann93690c22015-03-06 10:11:21 -08004020 err = new_settings(hdev, sk);
4021
4022unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004023 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004024 return err;
4025}
4026
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004027static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4028 void *data, u16 len)
4029{
4030 struct mgmt_cp_set_scan_params *cp = data;
4031 __u16 interval, window;
4032 int err;
4033
4034 BT_DBG("%s", hdev->name);
4035
4036 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004037 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4038 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004039
4040 interval = __le16_to_cpu(cp->interval);
4041
4042 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004043 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4044 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004045
4046 window = __le16_to_cpu(cp->window);
4047
4048 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004049 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4050 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004051
Marcel Holtmann899e1072013-10-14 09:55:32 -07004052 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004053 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4054 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004055
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004056 hci_dev_lock(hdev);
4057
4058 hdev->le_scan_interval = interval;
4059 hdev->le_scan_window = window;
4060
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004061 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4062 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004063
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004064 /* If background scan is running, restart it so new parameters are
4065 * loaded.
4066 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004067 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004068 hdev->discovery.state == DISCOVERY_STOPPED) {
4069 struct hci_request req;
4070
4071 hci_req_init(&req, hdev);
4072
4073 hci_req_add_le_scan_disable(&req);
4074 hci_req_add_le_passive_scan(&req);
4075
4076 hci_req_run(&req, NULL);
4077 }
4078
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004079 hci_dev_unlock(hdev);
4080
4081 return err;
4082}
4083
Marcel Holtmann1904a852015-01-11 13:50:44 -08004084static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4085 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004086{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004087 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004088
4089 BT_DBG("status 0x%02x", status);
4090
4091 hci_dev_lock(hdev);
4092
Johan Hedberg333ae952015-03-17 13:48:47 +02004093 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004094 if (!cmd)
4095 goto unlock;
4096
4097 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004098 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4099 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004100 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004101 struct mgmt_mode *cp = cmd->param;
4102
4103 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004104 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004105 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004106 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004107
Johan Hedberg33e38b32013-03-15 17:07:05 -05004108 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4109 new_settings(hdev, cmd->sk);
4110 }
4111
4112 mgmt_pending_remove(cmd);
4113
4114unlock:
4115 hci_dev_unlock(hdev);
4116}
4117
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004118static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004119 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004120{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004121 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004122 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004123 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004124 int err;
4125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004126 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004127
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004128 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004129 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004130 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4131 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004132
Johan Hedberga7e80f22013-01-09 16:05:19 +02004133 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004134 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4135 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004136
Antti Julkuf6422ec2011-06-22 13:11:56 +03004137 hci_dev_lock(hdev);
4138
Johan Hedberg333ae952015-03-17 13:48:47 +02004139 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004140 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4141 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004142 goto unlock;
4143 }
4144
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004145 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004146 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4147 hdev);
4148 goto unlock;
4149 }
4150
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004151 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004152 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004153 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4154 hdev);
4155 new_settings(hdev, sk);
4156 goto unlock;
4157 }
4158
Johan Hedberg33e38b32013-03-15 17:07:05 -05004159 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4160 data, len);
4161 if (!cmd) {
4162 err = -ENOMEM;
4163 goto unlock;
4164 }
4165
4166 hci_req_init(&req, hdev);
4167
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004168 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004169
4170 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004171 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004172 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4173 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004174 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004175 }
4176
Johan Hedberg33e38b32013-03-15 17:07:05 -05004177unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004178 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004179
Antti Julkuf6422ec2011-06-22 13:11:56 +03004180 return err;
4181}
4182
Marcel Holtmann1904a852015-01-11 13:50:44 -08004183static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004184{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004185 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004186
4187 BT_DBG("status 0x%02x", status);
4188
4189 hci_dev_lock(hdev);
4190
Johan Hedberg333ae952015-03-17 13:48:47 +02004191 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004192 if (!cmd)
4193 goto unlock;
4194
4195 if (status) {
4196 u8 mgmt_err = mgmt_status(status);
4197
4198 /* We need to restore the flag if related HCI commands
4199 * failed.
4200 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004201 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004202
Johan Hedberga69e8372015-03-06 21:08:53 +02004203 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004204 } else {
4205 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4206 new_settings(hdev, cmd->sk);
4207 }
4208
4209 mgmt_pending_remove(cmd);
4210
4211unlock:
4212 hci_dev_unlock(hdev);
4213}
4214
4215static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4216{
4217 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004218 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004219 struct hci_request req;
4220 int err;
4221
4222 BT_DBG("request for %s", hdev->name);
4223
4224 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004225 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4226 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004227
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004228 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004229 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4230 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004231
4232 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004233 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4234 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004235
4236 hci_dev_lock(hdev);
4237
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004238 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004239 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4240 goto unlock;
4241 }
4242
4243 if (!hdev_is_powered(hdev)) {
4244 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004245 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4246 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4247 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4248 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4249 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004250 }
4251
Marcel Holtmannce05d602015-03-13 02:11:03 -07004252 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004253
4254 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4255 if (err < 0)
4256 goto unlock;
4257
4258 err = new_settings(hdev, sk);
4259 goto unlock;
4260 }
4261
4262 /* Reject disabling when powered on */
4263 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004264 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4265 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004266 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004267 } else {
4268 /* When configuring a dual-mode controller to operate
4269 * with LE only and using a static address, then switching
4270 * BR/EDR back on is not allowed.
4271 *
4272 * Dual-mode controllers shall operate with the public
4273 * address as its identity address for BR/EDR and LE. So
4274 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004275 *
4276 * The same restrictions applies when secure connections
4277 * has been enabled. For BR/EDR this is a controller feature
4278 * while for LE it is a host stack feature. This means that
4279 * switching BR/EDR back on when secure connections has been
4280 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004281 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004282 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004283 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004284 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004285 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4286 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004287 goto unlock;
4288 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004289 }
4290
Johan Hedberg333ae952015-03-17 13:48:47 +02004291 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004292 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4293 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004294 goto unlock;
4295 }
4296
4297 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4298 if (!cmd) {
4299 err = -ENOMEM;
4300 goto unlock;
4301 }
4302
Johan Hedbergf2252572015-11-18 12:49:20 +02004303 /* We need to flip the bit already here so that
4304 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004305 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004306 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004307
4308 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004309
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004310 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004311 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004312
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004313 /* Since only the advertising data flags will change, there
4314 * is no need to update the scan response data.
4315 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004316 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004317
Johan Hedberg0663ca22013-10-02 13:43:14 +03004318 err = hci_req_run(&req, set_bredr_complete);
4319 if (err < 0)
4320 mgmt_pending_remove(cmd);
4321
4322unlock:
4323 hci_dev_unlock(hdev);
4324 return err;
4325}
4326
Johan Hedberga1443f52015-01-23 15:42:46 +02004327static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4328{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004329 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004330 struct mgmt_mode *cp;
4331
4332 BT_DBG("%s status %u", hdev->name, status);
4333
4334 hci_dev_lock(hdev);
4335
Johan Hedberg333ae952015-03-17 13:48:47 +02004336 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004337 if (!cmd)
4338 goto unlock;
4339
4340 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004341 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4342 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004343 goto remove;
4344 }
4345
4346 cp = cmd->param;
4347
4348 switch (cp->val) {
4349 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004350 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4351 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004352 break;
4353 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004354 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004355 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004356 break;
4357 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004358 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4359 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004360 break;
4361 }
4362
4363 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4364 new_settings(hdev, cmd->sk);
4365
4366remove:
4367 mgmt_pending_remove(cmd);
4368unlock:
4369 hci_dev_unlock(hdev);
4370}
4371
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004372static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4373 void *data, u16 len)
4374{
4375 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004376 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004377 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004378 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004379 int err;
4380
4381 BT_DBG("request for %s", hdev->name);
4382
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004383 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004384 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004385 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4386 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004387
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004388 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004389 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004390 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004391 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4392 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004393
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004394 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004395 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004396 MGMT_STATUS_INVALID_PARAMS);
4397
4398 hci_dev_lock(hdev);
4399
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004400 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004401 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004402 bool changed;
4403
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004404 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004405 changed = !hci_dev_test_and_set_flag(hdev,
4406 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004407 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004408 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004409 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004410 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004411 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004412 changed = hci_dev_test_and_clear_flag(hdev,
4413 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004414 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004415 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004416
4417 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4418 if (err < 0)
4419 goto failed;
4420
4421 if (changed)
4422 err = new_settings(hdev, sk);
4423
4424 goto failed;
4425 }
4426
Johan Hedberg333ae952015-03-17 13:48:47 +02004427 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004428 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4429 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004430 goto failed;
4431 }
4432
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004433 val = !!cp->val;
4434
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004435 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4436 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004437 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4438 goto failed;
4439 }
4440
4441 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4442 if (!cmd) {
4443 err = -ENOMEM;
4444 goto failed;
4445 }
4446
Johan Hedberga1443f52015-01-23 15:42:46 +02004447 hci_req_init(&req, hdev);
4448 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4449 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004450 if (err < 0) {
4451 mgmt_pending_remove(cmd);
4452 goto failed;
4453 }
4454
4455failed:
4456 hci_dev_unlock(hdev);
4457 return err;
4458}
4459
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004460static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4461 void *data, u16 len)
4462{
4463 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004464 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004465 int err;
4466
4467 BT_DBG("request for %s", hdev->name);
4468
Johan Hedbergb97109792014-06-24 14:00:28 +03004469 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004470 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4471 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004472
4473 hci_dev_lock(hdev);
4474
4475 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004476 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004477 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004478 changed = hci_dev_test_and_clear_flag(hdev,
4479 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004480
Johan Hedbergb97109792014-06-24 14:00:28 +03004481 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004482 use_changed = !hci_dev_test_and_set_flag(hdev,
4483 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004484 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004485 use_changed = hci_dev_test_and_clear_flag(hdev,
4486 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004487
4488 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004489 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004490 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4491 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4492 sizeof(mode), &mode);
4493 }
4494
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004495 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4496 if (err < 0)
4497 goto unlock;
4498
4499 if (changed)
4500 err = new_settings(hdev, sk);
4501
4502unlock:
4503 hci_dev_unlock(hdev);
4504 return err;
4505}
4506
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004507static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4508 u16 len)
4509{
4510 struct mgmt_cp_set_privacy *cp = cp_data;
4511 bool changed;
4512 int err;
4513
4514 BT_DBG("request for %s", hdev->name);
4515
4516 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004517 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4518 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004519
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004520 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004521 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4522 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004523
4524 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004525 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4526 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004527
4528 hci_dev_lock(hdev);
4529
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004530 /* If user space supports this command it is also expected to
4531 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4532 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004533 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004534
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004535 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004536 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004537 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004538 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004539 if (cp->privacy == 0x02)
4540 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4541 else
4542 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004543 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004544 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004545 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004546 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004547 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004548 }
4549
4550 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4551 if (err < 0)
4552 goto unlock;
4553
4554 if (changed)
4555 err = new_settings(hdev, sk);
4556
4557unlock:
4558 hci_dev_unlock(hdev);
4559 return err;
4560}
4561
Johan Hedberg41edf162014-02-18 10:19:35 +02004562static bool irk_is_valid(struct mgmt_irk_info *irk)
4563{
4564 switch (irk->addr.type) {
4565 case BDADDR_LE_PUBLIC:
4566 return true;
4567
4568 case BDADDR_LE_RANDOM:
4569 /* Two most significant bits shall be set */
4570 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4571 return false;
4572 return true;
4573 }
4574
4575 return false;
4576}
4577
4578static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4579 u16 len)
4580{
4581 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004582 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4583 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004584 u16 irk_count, expected_len;
4585 int i, err;
4586
4587 BT_DBG("request for %s", hdev->name);
4588
4589 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004590 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4591 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004592
4593 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004594 if (irk_count > max_irk_count) {
4595 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004596 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4597 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004598 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004599
4600 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4601 if (expected_len != len) {
4602 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004603 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004604 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4605 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004606 }
4607
4608 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4609
4610 for (i = 0; i < irk_count; i++) {
4611 struct mgmt_irk_info *key = &cp->irks[i];
4612
4613 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004614 return mgmt_cmd_status(sk, hdev->id,
4615 MGMT_OP_LOAD_IRKS,
4616 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004617 }
4618
4619 hci_dev_lock(hdev);
4620
4621 hci_smp_irks_clear(hdev);
4622
4623 for (i = 0; i < irk_count; i++) {
4624 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004625
Johan Hedberg85813a72015-10-21 18:02:59 +03004626 hci_add_irk(hdev, &irk->addr.bdaddr,
4627 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004628 BDADDR_ANY);
4629 }
4630
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004631 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004632
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004633 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004634
4635 hci_dev_unlock(hdev);
4636
4637 return err;
4638}
4639
Johan Hedberg3f706b72013-01-20 14:27:16 +02004640static bool ltk_is_valid(struct mgmt_ltk_info *key)
4641{
4642 if (key->master != 0x00 && key->master != 0x01)
4643 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004644
4645 switch (key->addr.type) {
4646 case BDADDR_LE_PUBLIC:
4647 return true;
4648
4649 case BDADDR_LE_RANDOM:
4650 /* Two most significant bits shall be set */
4651 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4652 return false;
4653 return true;
4654 }
4655
4656 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004657}
4658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004659static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004660 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004661{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004662 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004663 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4664 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004665 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004666 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004667
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004668 BT_DBG("request for %s", hdev->name);
4669
4670 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004671 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4672 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004673
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004674 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004675 if (key_count > max_key_count) {
4676 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4678 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004679 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004680
4681 expected_len = sizeof(*cp) + key_count *
4682 sizeof(struct mgmt_ltk_info);
4683 if (expected_len != len) {
4684 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004685 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004686 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4687 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004688 }
4689
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004690 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004691
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004692 for (i = 0; i < key_count; i++) {
4693 struct mgmt_ltk_info *key = &cp->keys[i];
4694
Johan Hedberg3f706b72013-01-20 14:27:16 +02004695 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004696 return mgmt_cmd_status(sk, hdev->id,
4697 MGMT_OP_LOAD_LONG_TERM_KEYS,
4698 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004699 }
4700
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004701 hci_dev_lock(hdev);
4702
4703 hci_smp_ltks_clear(hdev);
4704
4705 for (i = 0; i < key_count; i++) {
4706 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004707 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004708
Johan Hedberg61b43352014-05-29 19:36:53 +03004709 switch (key->type) {
4710 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004711 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004712 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004713 break;
4714 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004715 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004716 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004717 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004718 case MGMT_LTK_P256_UNAUTH:
4719 authenticated = 0x00;
4720 type = SMP_LTK_P256;
4721 break;
4722 case MGMT_LTK_P256_AUTH:
4723 authenticated = 0x01;
4724 type = SMP_LTK_P256;
4725 break;
4726 case MGMT_LTK_P256_DEBUG:
4727 authenticated = 0x00;
4728 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004729 default:
4730 continue;
4731 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004732
Johan Hedberg85813a72015-10-21 18:02:59 +03004733 hci_add_ltk(hdev, &key->addr.bdaddr,
4734 le_addr_type(key->addr.type), type, authenticated,
4735 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004736 }
4737
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004738 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004739 NULL, 0);
4740
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004741 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004742
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004743 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004744}
4745
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004746static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004747{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004748 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004749 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004750 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004751
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004752 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004753
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004754 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004755 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004756 rp.tx_power = conn->tx_power;
4757 rp.max_tx_power = conn->max_tx_power;
4758 } else {
4759 rp.rssi = HCI_RSSI_INVALID;
4760 rp.tx_power = HCI_TX_POWER_INVALID;
4761 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004762 }
4763
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004764 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4765 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004766
4767 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004768 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004769
4770 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004771}
4772
Marcel Holtmann1904a852015-01-11 13:50:44 -08004773static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4774 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004775{
4776 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004777 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004778 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004779 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004780 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004781
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004782 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004783
4784 hci_dev_lock(hdev);
4785
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004786 /* Commands sent in request are either Read RSSI or Read Transmit Power
4787 * Level so we check which one was last sent to retrieve connection
4788 * handle. Both commands have handle as first parameter so it's safe to
4789 * cast data on the same command struct.
4790 *
4791 * First command sent is always Read RSSI and we fail only if it fails.
4792 * In other case we simply override error to indicate success as we
4793 * already remembered if TX power value is actually valid.
4794 */
4795 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4796 if (!cp) {
4797 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004798 status = MGMT_STATUS_SUCCESS;
4799 } else {
4800 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004801 }
4802
4803 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004804 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004805 goto unlock;
4806 }
4807
4808 handle = __le16_to_cpu(cp->handle);
4809 conn = hci_conn_hash_lookup_handle(hdev, handle);
4810 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004811 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004812 goto unlock;
4813 }
4814
Johan Hedberg333ae952015-03-17 13:48:47 +02004815 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004816 if (!cmd)
4817 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004818
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004819 cmd->cmd_complete(cmd, status);
4820 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004821
4822unlock:
4823 hci_dev_unlock(hdev);
4824}
4825
4826static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4827 u16 len)
4828{
4829 struct mgmt_cp_get_conn_info *cp = data;
4830 struct mgmt_rp_get_conn_info rp;
4831 struct hci_conn *conn;
4832 unsigned long conn_info_age;
4833 int err = 0;
4834
4835 BT_DBG("%s", hdev->name);
4836
4837 memset(&rp, 0, sizeof(rp));
4838 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4839 rp.addr.type = cp->addr.type;
4840
4841 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004842 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4843 MGMT_STATUS_INVALID_PARAMS,
4844 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004845
4846 hci_dev_lock(hdev);
4847
4848 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004849 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4850 MGMT_STATUS_NOT_POWERED, &rp,
4851 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004852 goto unlock;
4853 }
4854
4855 if (cp->addr.type == BDADDR_BREDR)
4856 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4857 &cp->addr.bdaddr);
4858 else
4859 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4860
4861 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004862 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4863 MGMT_STATUS_NOT_CONNECTED, &rp,
4864 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004865 goto unlock;
4866 }
4867
Johan Hedberg333ae952015-03-17 13:48:47 +02004868 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004869 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4870 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004871 goto unlock;
4872 }
4873
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004874 /* To avoid client trying to guess when to poll again for information we
4875 * calculate conn info age as random value between min/max set in hdev.
4876 */
4877 conn_info_age = hdev->conn_info_min_age +
4878 prandom_u32_max(hdev->conn_info_max_age -
4879 hdev->conn_info_min_age);
4880
4881 /* Query controller to refresh cached values if they are too old or were
4882 * never read.
4883 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004884 if (time_after(jiffies, conn->conn_info_timestamp +
4885 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004886 !conn->conn_info_timestamp) {
4887 struct hci_request req;
4888 struct hci_cp_read_tx_power req_txp_cp;
4889 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004890 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004891
4892 hci_req_init(&req, hdev);
4893 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4894 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4895 &req_rssi_cp);
4896
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004897 /* For LE links TX power does not change thus we don't need to
4898 * query for it once value is known.
4899 */
4900 if (!bdaddr_type_is_le(cp->addr.type) ||
4901 conn->tx_power == HCI_TX_POWER_INVALID) {
4902 req_txp_cp.handle = cpu_to_le16(conn->handle);
4903 req_txp_cp.type = 0x00;
4904 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4905 sizeof(req_txp_cp), &req_txp_cp);
4906 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004907
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004908 /* Max TX power needs to be read only once per connection */
4909 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4910 req_txp_cp.handle = cpu_to_le16(conn->handle);
4911 req_txp_cp.type = 0x01;
4912 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4913 sizeof(req_txp_cp), &req_txp_cp);
4914 }
4915
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004916 err = hci_req_run(&req, conn_info_refresh_complete);
4917 if (err < 0)
4918 goto unlock;
4919
4920 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4921 data, len);
4922 if (!cmd) {
4923 err = -ENOMEM;
4924 goto unlock;
4925 }
4926
4927 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004928 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004929 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004930
4931 conn->conn_info_timestamp = jiffies;
4932 } else {
4933 /* Cache is valid, just reply with values cached in hci_conn */
4934 rp.rssi = conn->rssi;
4935 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004936 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004937
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004938 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4939 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004940 }
4941
4942unlock:
4943 hci_dev_unlock(hdev);
4944 return err;
4945}
4946
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004947static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004948{
4949 struct hci_conn *conn = cmd->user_data;
4950 struct mgmt_rp_get_clock_info rp;
4951 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004952 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004953
4954 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02004955 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02004956
4957 if (status)
4958 goto complete;
4959
4960 hdev = hci_dev_get(cmd->index);
4961 if (hdev) {
4962 rp.local_clock = cpu_to_le32(hdev->clock);
4963 hci_dev_put(hdev);
4964 }
4965
4966 if (conn) {
4967 rp.piconet_clock = cpu_to_le32(conn->clock);
4968 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
4969 }
4970
4971complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004972 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
4973 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02004974
4975 if (conn) {
4976 hci_conn_drop(conn);
4977 hci_conn_put(conn);
4978 }
Johan Hedberg9df74652014-12-19 22:26:03 +02004979
4980 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02004981}
4982
Marcel Holtmann1904a852015-01-11 13:50:44 -08004983static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03004984{
Johan Hedberg95868422014-06-28 17:54:07 +03004985 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004986 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004987 struct hci_conn *conn;
4988
4989 BT_DBG("%s status %u", hdev->name, status);
4990
4991 hci_dev_lock(hdev);
4992
4993 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
4994 if (!hci_cp)
4995 goto unlock;
4996
4997 if (hci_cp->which) {
4998 u16 handle = __le16_to_cpu(hci_cp->handle);
4999 conn = hci_conn_hash_lookup_handle(hdev, handle);
5000 } else {
5001 conn = NULL;
5002 }
5003
Johan Hedberg333ae952015-03-17 13:48:47 +02005004 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005005 if (!cmd)
5006 goto unlock;
5007
Johan Hedberg69487372014-12-05 13:36:07 +02005008 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005009 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005010
5011unlock:
5012 hci_dev_unlock(hdev);
5013}
5014
5015static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5016 u16 len)
5017{
5018 struct mgmt_cp_get_clock_info *cp = data;
5019 struct mgmt_rp_get_clock_info rp;
5020 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005021 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005022 struct hci_request req;
5023 struct hci_conn *conn;
5024 int err;
5025
5026 BT_DBG("%s", hdev->name);
5027
5028 memset(&rp, 0, sizeof(rp));
5029 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5030 rp.addr.type = cp->addr.type;
5031
5032 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005033 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5034 MGMT_STATUS_INVALID_PARAMS,
5035 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005036
5037 hci_dev_lock(hdev);
5038
5039 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005040 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5041 MGMT_STATUS_NOT_POWERED, &rp,
5042 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005043 goto unlock;
5044 }
5045
5046 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5047 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5048 &cp->addr.bdaddr);
5049 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005050 err = mgmt_cmd_complete(sk, hdev->id,
5051 MGMT_OP_GET_CLOCK_INFO,
5052 MGMT_STATUS_NOT_CONNECTED,
5053 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005054 goto unlock;
5055 }
5056 } else {
5057 conn = NULL;
5058 }
5059
5060 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5061 if (!cmd) {
5062 err = -ENOMEM;
5063 goto unlock;
5064 }
5065
Johan Hedberg69487372014-12-05 13:36:07 +02005066 cmd->cmd_complete = clock_info_cmd_complete;
5067
Johan Hedberg95868422014-06-28 17:54:07 +03005068 hci_req_init(&req, hdev);
5069
5070 memset(&hci_cp, 0, sizeof(hci_cp));
5071 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5072
5073 if (conn) {
5074 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005075 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005076
5077 hci_cp.handle = cpu_to_le16(conn->handle);
5078 hci_cp.which = 0x01; /* Piconet clock */
5079 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5080 }
5081
5082 err = hci_req_run(&req, get_clock_info_complete);
5083 if (err < 0)
5084 mgmt_pending_remove(cmd);
5085
5086unlock:
5087 hci_dev_unlock(hdev);
5088 return err;
5089}
5090
Johan Hedberg5a154e62014-12-19 22:26:02 +02005091static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5092{
5093 struct hci_conn *conn;
5094
5095 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5096 if (!conn)
5097 return false;
5098
5099 if (conn->dst_type != type)
5100 return false;
5101
5102 if (conn->state != BT_CONNECTED)
5103 return false;
5104
5105 return true;
5106}
5107
5108/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005109static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005110 u8 addr_type, u8 auto_connect)
5111{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005112 struct hci_conn_params *params;
5113
5114 params = hci_conn_params_add(hdev, addr, addr_type);
5115 if (!params)
5116 return -EIO;
5117
5118 if (params->auto_connect == auto_connect)
5119 return 0;
5120
5121 list_del_init(&params->action);
5122
5123 switch (auto_connect) {
5124 case HCI_AUTO_CONN_DISABLED:
5125 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005126 /* If auto connect is being disabled when we're trying to
5127 * connect to device, keep connecting.
5128 */
5129 if (params->explicit_connect)
5130 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005131 break;
5132 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005133 if (params->explicit_connect)
5134 list_add(&params->action, &hdev->pend_le_conns);
5135 else
5136 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005137 break;
5138 case HCI_AUTO_CONN_DIRECT:
5139 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005140 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005141 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005142 break;
5143 }
5144
5145 params->auto_connect = auto_connect;
5146
5147 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5148 auto_connect);
5149
5150 return 0;
5151}
5152
Marcel Holtmann8afef092014-06-29 22:28:34 +02005153static void device_added(struct sock *sk, struct hci_dev *hdev,
5154 bdaddr_t *bdaddr, u8 type, u8 action)
5155{
5156 struct mgmt_ev_device_added ev;
5157
5158 bacpy(&ev.addr.bdaddr, bdaddr);
5159 ev.addr.type = type;
5160 ev.action = action;
5161
5162 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5163}
5164
Marcel Holtmann2faade52014-06-29 19:44:03 +02005165static int add_device(struct sock *sk, struct hci_dev *hdev,
5166 void *data, u16 len)
5167{
5168 struct mgmt_cp_add_device *cp = data;
5169 u8 auto_conn, addr_type;
5170 int err;
5171
5172 BT_DBG("%s", hdev->name);
5173
Johan Hedberg66593582014-07-09 12:59:14 +03005174 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005175 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005176 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5177 MGMT_STATUS_INVALID_PARAMS,
5178 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005179
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005180 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005181 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5182 MGMT_STATUS_INVALID_PARAMS,
5183 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005184
5185 hci_dev_lock(hdev);
5186
Johan Hedberg66593582014-07-09 12:59:14 +03005187 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005188 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005189 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005190 err = mgmt_cmd_complete(sk, hdev->id,
5191 MGMT_OP_ADD_DEVICE,
5192 MGMT_STATUS_INVALID_PARAMS,
5193 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005194 goto unlock;
5195 }
5196
5197 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5198 cp->addr.type);
5199 if (err)
5200 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005201
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005202 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005203
Johan Hedberg66593582014-07-09 12:59:14 +03005204 goto added;
5205 }
5206
Johan Hedberg85813a72015-10-21 18:02:59 +03005207 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005208
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005209 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005210 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005211 else if (cp->action == 0x01)
5212 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005213 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005214 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005215
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005216 /* Kernel internally uses conn_params with resolvable private
5217 * address, but Add Device allows only identity addresses.
5218 * Make sure it is enforced before calling
5219 * hci_conn_params_lookup.
5220 */
5221 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005222 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5223 MGMT_STATUS_INVALID_PARAMS,
5224 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005225 goto unlock;
5226 }
5227
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005228 /* If the connection parameters don't exist for this device,
5229 * they will be created and configured with defaults.
5230 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005231 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005232 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005233 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5234 MGMT_STATUS_FAILED, &cp->addr,
5235 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005236 goto unlock;
5237 }
5238
Johan Hedberg51d7a942015-11-11 08:11:18 +02005239 hci_update_background_scan(hdev);
5240
Johan Hedberg66593582014-07-09 12:59:14 +03005241added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005242 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5243
Johan Hedberg51d7a942015-11-11 08:11:18 +02005244 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5245 MGMT_STATUS_SUCCESS, &cp->addr,
5246 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005247
5248unlock:
5249 hci_dev_unlock(hdev);
5250 return err;
5251}
5252
Marcel Holtmann8afef092014-06-29 22:28:34 +02005253static void device_removed(struct sock *sk, struct hci_dev *hdev,
5254 bdaddr_t *bdaddr, u8 type)
5255{
5256 struct mgmt_ev_device_removed ev;
5257
5258 bacpy(&ev.addr.bdaddr, bdaddr);
5259 ev.addr.type = type;
5260
5261 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5262}
5263
Marcel Holtmann2faade52014-06-29 19:44:03 +02005264static int remove_device(struct sock *sk, struct hci_dev *hdev,
5265 void *data, u16 len)
5266{
5267 struct mgmt_cp_remove_device *cp = data;
5268 int err;
5269
5270 BT_DBG("%s", hdev->name);
5271
5272 hci_dev_lock(hdev);
5273
5274 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005275 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005276 u8 addr_type;
5277
Johan Hedberg66593582014-07-09 12:59:14 +03005278 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005279 err = mgmt_cmd_complete(sk, hdev->id,
5280 MGMT_OP_REMOVE_DEVICE,
5281 MGMT_STATUS_INVALID_PARAMS,
5282 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005283 goto unlock;
5284 }
5285
Johan Hedberg66593582014-07-09 12:59:14 +03005286 if (cp->addr.type == BDADDR_BREDR) {
5287 err = hci_bdaddr_list_del(&hdev->whitelist,
5288 &cp->addr.bdaddr,
5289 cp->addr.type);
5290 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005291 err = mgmt_cmd_complete(sk, hdev->id,
5292 MGMT_OP_REMOVE_DEVICE,
5293 MGMT_STATUS_INVALID_PARAMS,
5294 &cp->addr,
5295 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005296 goto unlock;
5297 }
5298
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005299 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005300
Johan Hedberg66593582014-07-09 12:59:14 +03005301 device_removed(sk, hdev, &cp->addr.bdaddr,
5302 cp->addr.type);
5303 goto complete;
5304 }
5305
Johan Hedberg85813a72015-10-21 18:02:59 +03005306 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005307
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005308 /* Kernel internally uses conn_params with resolvable private
5309 * address, but Remove Device allows only identity addresses.
5310 * Make sure it is enforced before calling
5311 * hci_conn_params_lookup.
5312 */
5313 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005314 err = mgmt_cmd_complete(sk, hdev->id,
5315 MGMT_OP_REMOVE_DEVICE,
5316 MGMT_STATUS_INVALID_PARAMS,
5317 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005318 goto unlock;
5319 }
5320
Johan Hedbergc71593d2014-07-02 17:37:28 +03005321 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5322 addr_type);
5323 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005324 err = mgmt_cmd_complete(sk, hdev->id,
5325 MGMT_OP_REMOVE_DEVICE,
5326 MGMT_STATUS_INVALID_PARAMS,
5327 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005328 goto unlock;
5329 }
5330
Johan Hedberg679d2b62015-10-16 10:07:52 +03005331 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5332 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005333 err = mgmt_cmd_complete(sk, hdev->id,
5334 MGMT_OP_REMOVE_DEVICE,
5335 MGMT_STATUS_INVALID_PARAMS,
5336 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005337 goto unlock;
5338 }
5339
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005340 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005341 list_del(&params->list);
5342 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005343 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005344
5345 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005346 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005347 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005348 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005349
Marcel Holtmann2faade52014-06-29 19:44:03 +02005350 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005351 err = mgmt_cmd_complete(sk, hdev->id,
5352 MGMT_OP_REMOVE_DEVICE,
5353 MGMT_STATUS_INVALID_PARAMS,
5354 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005355 goto unlock;
5356 }
5357
Johan Hedberg66593582014-07-09 12:59:14 +03005358 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5359 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5360 list_del(&b->list);
5361 kfree(b);
5362 }
5363
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005364 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005365
Johan Hedberg19de0822014-07-06 13:06:51 +03005366 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5367 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5368 continue;
5369 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005370 if (p->explicit_connect) {
5371 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5372 continue;
5373 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005374 list_del(&p->action);
5375 list_del(&p->list);
5376 kfree(p);
5377 }
5378
5379 BT_DBG("All LE connection parameters were removed");
5380
Johan Hedberg51d7a942015-11-11 08:11:18 +02005381 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005382 }
5383
Johan Hedberg66593582014-07-09 12:59:14 +03005384complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005385 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5386 MGMT_STATUS_SUCCESS, &cp->addr,
5387 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005388unlock:
5389 hci_dev_unlock(hdev);
5390 return err;
5391}
5392
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005393static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5394 u16 len)
5395{
5396 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005397 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5398 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005399 u16 param_count, expected_len;
5400 int i;
5401
5402 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005403 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5404 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005405
5406 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005407 if (param_count > max_param_count) {
5408 BT_ERR("load_conn_param: too big param_count value %u",
5409 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005410 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5411 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005412 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005413
5414 expected_len = sizeof(*cp) + param_count *
5415 sizeof(struct mgmt_conn_param);
5416 if (expected_len != len) {
5417 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5418 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005419 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5420 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005421 }
5422
5423 BT_DBG("%s param_count %u", hdev->name, param_count);
5424
5425 hci_dev_lock(hdev);
5426
5427 hci_conn_params_clear_disabled(hdev);
5428
5429 for (i = 0; i < param_count; i++) {
5430 struct mgmt_conn_param *param = &cp->params[i];
5431 struct hci_conn_params *hci_param;
5432 u16 min, max, latency, timeout;
5433 u8 addr_type;
5434
5435 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5436 param->addr.type);
5437
5438 if (param->addr.type == BDADDR_LE_PUBLIC) {
5439 addr_type = ADDR_LE_DEV_PUBLIC;
5440 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5441 addr_type = ADDR_LE_DEV_RANDOM;
5442 } else {
5443 BT_ERR("Ignoring invalid connection parameters");
5444 continue;
5445 }
5446
5447 min = le16_to_cpu(param->min_interval);
5448 max = le16_to_cpu(param->max_interval);
5449 latency = le16_to_cpu(param->latency);
5450 timeout = le16_to_cpu(param->timeout);
5451
5452 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5453 min, max, latency, timeout);
5454
5455 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5456 BT_ERR("Ignoring invalid connection parameters");
5457 continue;
5458 }
5459
5460 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5461 addr_type);
5462 if (!hci_param) {
5463 BT_ERR("Failed to add connection parameters");
5464 continue;
5465 }
5466
5467 hci_param->conn_min_interval = min;
5468 hci_param->conn_max_interval = max;
5469 hci_param->conn_latency = latency;
5470 hci_param->supervision_timeout = timeout;
5471 }
5472
5473 hci_dev_unlock(hdev);
5474
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005475 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5476 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005477}
5478
Marcel Holtmanndbece372014-07-04 18:11:55 +02005479static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5480 void *data, u16 len)
5481{
5482 struct mgmt_cp_set_external_config *cp = data;
5483 bool changed;
5484 int err;
5485
5486 BT_DBG("%s", hdev->name);
5487
5488 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005489 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5490 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005491
5492 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005493 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5494 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005495
5496 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005497 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5498 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005499
5500 hci_dev_lock(hdev);
5501
5502 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005503 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005504 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005505 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005506
5507 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5508 if (err < 0)
5509 goto unlock;
5510
5511 if (!changed)
5512 goto unlock;
5513
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005514 err = new_options(hdev, sk);
5515
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005516 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005517 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005518
Marcel Holtmann516018a2015-03-13 02:11:04 -07005519 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005520 hci_dev_set_flag(hdev, HCI_CONFIG);
5521 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005522
5523 queue_work(hdev->req_workqueue, &hdev->power_on);
5524 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005525 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005526 mgmt_index_added(hdev);
5527 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005528 }
5529
5530unlock:
5531 hci_dev_unlock(hdev);
5532 return err;
5533}
5534
Marcel Holtmann9713c172014-07-06 12:11:15 +02005535static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5536 void *data, u16 len)
5537{
5538 struct mgmt_cp_set_public_address *cp = data;
5539 bool changed;
5540 int err;
5541
5542 BT_DBG("%s", hdev->name);
5543
5544 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005545 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5546 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005547
5548 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005549 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5550 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005551
5552 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005553 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5554 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005555
5556 hci_dev_lock(hdev);
5557
5558 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5559 bacpy(&hdev->public_addr, &cp->bdaddr);
5560
5561 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5562 if (err < 0)
5563 goto unlock;
5564
5565 if (!changed)
5566 goto unlock;
5567
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005568 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005569 err = new_options(hdev, sk);
5570
5571 if (is_configured(hdev)) {
5572 mgmt_index_removed(hdev);
5573
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005574 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005575
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005576 hci_dev_set_flag(hdev, HCI_CONFIG);
5577 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005578
5579 queue_work(hdev->req_workqueue, &hdev->power_on);
5580 }
5581
5582unlock:
5583 hci_dev_unlock(hdev);
5584 return err;
5585}
5586
Johan Hedberg40f66c02015-04-07 21:52:22 +03005587static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5588 u16 opcode, struct sk_buff *skb)
5589{
5590 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5591 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5592 u8 *h192, *r192, *h256, *r256;
5593 struct mgmt_pending_cmd *cmd;
5594 u16 eir_len;
5595 int err;
5596
5597 BT_DBG("%s status %u", hdev->name, status);
5598
5599 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5600 if (!cmd)
5601 return;
5602
5603 mgmt_cp = cmd->param;
5604
5605 if (status) {
5606 status = mgmt_status(status);
5607 eir_len = 0;
5608
5609 h192 = NULL;
5610 r192 = NULL;
5611 h256 = NULL;
5612 r256 = NULL;
5613 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5614 struct hci_rp_read_local_oob_data *rp;
5615
5616 if (skb->len != sizeof(*rp)) {
5617 status = MGMT_STATUS_FAILED;
5618 eir_len = 0;
5619 } else {
5620 status = MGMT_STATUS_SUCCESS;
5621 rp = (void *)skb->data;
5622
5623 eir_len = 5 + 18 + 18;
5624 h192 = rp->hash;
5625 r192 = rp->rand;
5626 h256 = NULL;
5627 r256 = NULL;
5628 }
5629 } else {
5630 struct hci_rp_read_local_oob_ext_data *rp;
5631
5632 if (skb->len != sizeof(*rp)) {
5633 status = MGMT_STATUS_FAILED;
5634 eir_len = 0;
5635 } else {
5636 status = MGMT_STATUS_SUCCESS;
5637 rp = (void *)skb->data;
5638
5639 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5640 eir_len = 5 + 18 + 18;
5641 h192 = NULL;
5642 r192 = NULL;
5643 } else {
5644 eir_len = 5 + 18 + 18 + 18 + 18;
5645 h192 = rp->hash192;
5646 r192 = rp->rand192;
5647 }
5648
5649 h256 = rp->hash256;
5650 r256 = rp->rand256;
5651 }
5652 }
5653
5654 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5655 if (!mgmt_rp)
5656 goto done;
5657
5658 if (status)
5659 goto send_rsp;
5660
5661 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5662 hdev->dev_class, 3);
5663
5664 if (h192 && r192) {
5665 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5666 EIR_SSP_HASH_C192, h192, 16);
5667 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5668 EIR_SSP_RAND_R192, r192, 16);
5669 }
5670
5671 if (h256 && r256) {
5672 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5673 EIR_SSP_HASH_C256, h256, 16);
5674 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5675 EIR_SSP_RAND_R256, r256, 16);
5676 }
5677
5678send_rsp:
5679 mgmt_rp->type = mgmt_cp->type;
5680 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5681
5682 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5683 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5684 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5685 if (err < 0 || status)
5686 goto done;
5687
5688 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5689
5690 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5691 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5692 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5693done:
5694 kfree(mgmt_rp);
5695 mgmt_pending_remove(cmd);
5696}
5697
5698static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5699 struct mgmt_cp_read_local_oob_ext_data *cp)
5700{
5701 struct mgmt_pending_cmd *cmd;
5702 struct hci_request req;
5703 int err;
5704
5705 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5706 cp, sizeof(*cp));
5707 if (!cmd)
5708 return -ENOMEM;
5709
5710 hci_req_init(&req, hdev);
5711
5712 if (bredr_sc_enabled(hdev))
5713 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5714 else
5715 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5716
5717 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5718 if (err < 0) {
5719 mgmt_pending_remove(cmd);
5720 return err;
5721 }
5722
5723 return 0;
5724}
5725
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005726static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5727 void *data, u16 data_len)
5728{
5729 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5730 struct mgmt_rp_read_local_oob_ext_data *rp;
5731 size_t rp_len;
5732 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005733 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005734 int err;
5735
5736 BT_DBG("%s", hdev->name);
5737
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005738 if (hdev_is_powered(hdev)) {
5739 switch (cp->type) {
5740 case BIT(BDADDR_BREDR):
5741 status = mgmt_bredr_support(hdev);
5742 if (status)
5743 eir_len = 0;
5744 else
5745 eir_len = 5;
5746 break;
5747 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5748 status = mgmt_le_support(hdev);
5749 if (status)
5750 eir_len = 0;
5751 else
5752 eir_len = 9 + 3 + 18 + 18 + 3;
5753 break;
5754 default:
5755 status = MGMT_STATUS_INVALID_PARAMS;
5756 eir_len = 0;
5757 break;
5758 }
5759 } else {
5760 status = MGMT_STATUS_NOT_POWERED;
5761 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005762 }
5763
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005764 rp_len = sizeof(*rp) + eir_len;
5765 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005766 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005767 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005768
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005769 if (status)
5770 goto complete;
5771
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005772 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005773
5774 eir_len = 0;
5775 switch (cp->type) {
5776 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005777 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5778 err = read_local_ssp_oob_req(hdev, sk, cp);
5779 hci_dev_unlock(hdev);
5780 if (!err)
5781 goto done;
5782
5783 status = MGMT_STATUS_FAILED;
5784 goto complete;
5785 } else {
5786 eir_len = eir_append_data(rp->eir, eir_len,
5787 EIR_CLASS_OF_DEV,
5788 hdev->dev_class, 3);
5789 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005790 break;
5791 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005792 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5793 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005794 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005795 status = MGMT_STATUS_FAILED;
5796 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005797 }
5798
Marcel Holtmanne2135682015-04-02 12:00:58 -07005799 /* This should return the active RPA, but since the RPA
5800 * is only programmed on demand, it is really hard to fill
5801 * this in at the moment. For now disallow retrieving
5802 * local out-of-band data when privacy is in use.
5803 *
5804 * Returning the identity address will not help here since
5805 * pairing happens before the identity resolving key is
5806 * known and thus the connection establishment happens
5807 * based on the RPA and not the identity address.
5808 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005809 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005810 hci_dev_unlock(hdev);
5811 status = MGMT_STATUS_REJECTED;
5812 goto complete;
5813 }
5814
5815 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5816 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5817 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5818 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005819 memcpy(addr, &hdev->static_addr, 6);
5820 addr[6] = 0x01;
5821 } else {
5822 memcpy(addr, &hdev->bdaddr, 6);
5823 addr[6] = 0x00;
5824 }
5825
5826 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5827 addr, sizeof(addr));
5828
5829 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5830 role = 0x02;
5831 else
5832 role = 0x01;
5833
5834 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5835 &role, sizeof(role));
5836
Marcel Holtmann5082a592015-03-16 12:39:00 -07005837 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5838 eir_len = eir_append_data(rp->eir, eir_len,
5839 EIR_LE_SC_CONFIRM,
5840 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005841
Marcel Holtmann5082a592015-03-16 12:39:00 -07005842 eir_len = eir_append_data(rp->eir, eir_len,
5843 EIR_LE_SC_RANDOM,
5844 rand, sizeof(rand));
5845 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005846
Johan Hedbergf2252572015-11-18 12:49:20 +02005847 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005848
5849 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5850 flags |= LE_AD_NO_BREDR;
5851
5852 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5853 &flags, sizeof(flags));
5854 break;
5855 }
5856
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005857 hci_dev_unlock(hdev);
5858
Marcel Holtmann72000df2015-03-16 16:11:21 -07005859 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5860
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005861 status = MGMT_STATUS_SUCCESS;
5862
5863complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005864 rp->type = cp->type;
5865 rp->eir_len = cpu_to_le16(eir_len);
5866
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005867 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005868 status, rp, sizeof(*rp) + eir_len);
5869 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005870 goto done;
5871
5872 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5873 rp, sizeof(*rp) + eir_len,
5874 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005875
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005876done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005877 kfree(rp);
5878
5879 return err;
5880}
5881
Arman Uguray089fa8c2015-03-25 18:53:45 -07005882static u32 get_supported_adv_flags(struct hci_dev *hdev)
5883{
5884 u32 flags = 0;
5885
5886 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5887 flags |= MGMT_ADV_FLAG_DISCOV;
5888 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5889 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
5890
5891 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5892 flags |= MGMT_ADV_FLAG_TX_POWER;
5893
5894 return flags;
5895}
5896
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005897static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5898 void *data, u16 data_len)
5899{
5900 struct mgmt_rp_read_adv_features *rp;
5901 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005902 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005903 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005904 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005905 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005906
5907 BT_DBG("%s", hdev->name);
5908
Arman Uguray089fa8c2015-03-25 18:53:45 -07005909 if (!lmp_le_capable(hdev))
5910 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5911 MGMT_STATUS_REJECTED);
5912
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005913 hci_dev_lock(hdev);
5914
Johan Hedberg02c04af2015-11-26 12:15:58 +02005915 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005916 rp = kmalloc(rp_len, GFP_ATOMIC);
5917 if (!rp) {
5918 hci_dev_unlock(hdev);
5919 return -ENOMEM;
5920 }
5921
Arman Uguray089fa8c2015-03-25 18:53:45 -07005922 supported_flags = get_supported_adv_flags(hdev);
5923
5924 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005925 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5926 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005927 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005928 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005929
Johan Hedberg02c04af2015-11-26 12:15:58 +02005930 instance = rp->instance;
5931 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5932 *instance = adv_instance->instance;
5933 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005934 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005935
5936 hci_dev_unlock(hdev);
5937
5938 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5939 MGMT_STATUS_SUCCESS, rp, rp_len);
5940
5941 kfree(rp);
5942
5943 return err;
5944}
5945
Arman Uguray4117ed72015-03-23 15:57:14 -07005946static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005947 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005948{
Arman Uguray4117ed72015-03-23 15:57:14 -07005949 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005950 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005951 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005952 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005953
Marcel Holtmann31a32482015-11-19 16:16:42 +01005954 if (is_adv_data) {
5955 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5956 MGMT_ADV_FLAG_LIMITED_DISCOV |
5957 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5958 flags_managed = true;
5959 max_len -= 3;
5960 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005961
Marcel Holtmann31a32482015-11-19 16:16:42 +01005962 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5963 tx_power_managed = true;
5964 max_len -= 3;
5965 }
Arman Uguray5507e352015-03-25 18:53:44 -07005966 }
5967
Arman Uguray4117ed72015-03-23 15:57:14 -07005968 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005969 return false;
5970
Arman Uguray4117ed72015-03-23 15:57:14 -07005971 /* Make sure that the data is correctly formatted. */
5972 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
5973 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07005974
Arman Ugurayb44133f2015-03-25 18:53:41 -07005975 if (flags_managed && data[i + 1] == EIR_FLAGS)
5976 return false;
5977
Arman Uguray5507e352015-03-25 18:53:44 -07005978 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
5979 return false;
5980
Arman Uguray24b4f382015-03-23 15:57:12 -07005981 /* If the current field length would exceed the total data
5982 * length, then it's invalid.
5983 */
Arman Uguray4117ed72015-03-23 15:57:14 -07005984 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005985 return false;
5986 }
5987
5988 return true;
5989}
5990
Arman Uguray24b4f382015-03-23 15:57:12 -07005991static void add_advertising_complete(struct hci_dev *hdev, u8 status,
5992 u16 opcode)
5993{
5994 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005995 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07005996 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005997 struct adv_info *adv_instance, *n;
5998 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005999
6000 BT_DBG("status %d", status);
6001
6002 hci_dev_lock(hdev);
6003
6004 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6005
Florian Grandelfffd38b2015-06-18 03:16:47 +02006006 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
6007 if (!adv_instance->pending)
6008 continue;
6009
6010 if (!status) {
6011 adv_instance->pending = false;
6012 continue;
6013 }
6014
6015 instance = adv_instance->instance;
6016
6017 if (hdev->cur_adv_instance == instance)
6018 cancel_adv_timeout(hdev);
6019
6020 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006021 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006022 }
6023
6024 if (!cmd)
6025 goto unlock;
6026
Florian Grandelfffd38b2015-06-18 03:16:47 +02006027 cp = cmd->param;
6028 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006029
6030 if (status)
6031 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6032 mgmt_status(status));
6033 else
6034 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6035 mgmt_status(status), &rp, sizeof(rp));
6036
6037 mgmt_pending_remove(cmd);
6038
6039unlock:
6040 hci_dev_unlock(hdev);
6041}
6042
6043static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6044 void *data, u16 data_len)
6045{
6046 struct mgmt_cp_add_advertising *cp = data;
6047 struct mgmt_rp_add_advertising rp;
6048 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006049 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006050 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006051 u16 timeout, duration;
6052 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6053 u8 schedule_instance = 0;
6054 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006055 int err;
6056 struct mgmt_pending_cmd *cmd;
6057 struct hci_request req;
6058
6059 BT_DBG("%s", hdev->name);
6060
6061 status = mgmt_le_support(hdev);
6062 if (status)
6063 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6064 status);
6065
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006066 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6067 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6068 MGMT_STATUS_INVALID_PARAMS);
6069
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006070 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6071 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6072 MGMT_STATUS_INVALID_PARAMS);
6073
Arman Uguray24b4f382015-03-23 15:57:12 -07006074 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006075 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006076 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006077
Florian Grandelfffd38b2015-06-18 03:16:47 +02006078 /* The current implementation only supports a subset of the specified
6079 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006080 */
6081 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006082 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006083 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6084 MGMT_STATUS_INVALID_PARAMS);
6085
6086 hci_dev_lock(hdev);
6087
Arman Uguray912098a2015-03-23 15:57:15 -07006088 if (timeout && !hdev_is_powered(hdev)) {
6089 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6090 MGMT_STATUS_REJECTED);
6091 goto unlock;
6092 }
6093
Arman Uguray24b4f382015-03-23 15:57:12 -07006094 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006095 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006096 pending_find(MGMT_OP_SET_LE, hdev)) {
6097 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6098 MGMT_STATUS_BUSY);
6099 goto unlock;
6100 }
6101
Arman Ugurayb44133f2015-03-25 18:53:41 -07006102 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006103 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006104 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006105 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6106 MGMT_STATUS_INVALID_PARAMS);
6107 goto unlock;
6108 }
6109
Florian Grandelfffd38b2015-06-18 03:16:47 +02006110 err = hci_add_adv_instance(hdev, cp->instance, flags,
6111 cp->adv_data_len, cp->data,
6112 cp->scan_rsp_len,
6113 cp->data + cp->adv_data_len,
6114 timeout, duration);
6115 if (err < 0) {
6116 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6117 MGMT_STATUS_FAILED);
6118 goto unlock;
6119 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006120
Florian Grandelfffd38b2015-06-18 03:16:47 +02006121 /* Only trigger an advertising added event if a new instance was
6122 * actually added.
6123 */
6124 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006125 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006126
Florian Grandelfffd38b2015-06-18 03:16:47 +02006127 if (hdev->cur_adv_instance == cp->instance) {
6128 /* If the currently advertised instance is being changed then
6129 * cancel the current advertising and schedule the next
6130 * instance. If there is only one instance then the overridden
6131 * advertising data will be visible right away.
6132 */
6133 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006134
Florian Grandelfffd38b2015-06-18 03:16:47 +02006135 next_instance = hci_get_next_instance(hdev, cp->instance);
6136 if (next_instance)
6137 schedule_instance = next_instance->instance;
6138 } else if (!hdev->adv_instance_timeout) {
6139 /* Immediately advertise the new instance if no other
6140 * instance is currently being advertised.
6141 */
6142 schedule_instance = cp->instance;
6143 }
Arman Uguray912098a2015-03-23 15:57:15 -07006144
Florian Grandelfffd38b2015-06-18 03:16:47 +02006145 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6146 * there is no instance to be advertised then we have no HCI
6147 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006148 */
6149 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006150 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6151 !schedule_instance) {
6152 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006153 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6154 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6155 goto unlock;
6156 }
6157
6158 /* We're good to go, update advertising data, parameters, and start
6159 * advertising.
6160 */
6161 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6162 data_len);
6163 if (!cmd) {
6164 err = -ENOMEM;
6165 goto unlock;
6166 }
6167
6168 hci_req_init(&req, hdev);
6169
Johan Hedbergf2252572015-11-18 12:49:20 +02006170 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006171
Florian Grandelfffd38b2015-06-18 03:16:47 +02006172 if (!err)
6173 err = hci_req_run(&req, add_advertising_complete);
6174
Arman Uguray24b4f382015-03-23 15:57:12 -07006175 if (err < 0)
6176 mgmt_pending_remove(cmd);
6177
6178unlock:
6179 hci_dev_unlock(hdev);
6180
6181 return err;
6182}
6183
Arman Ugurayda9293352015-03-23 15:57:13 -07006184static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6185 u16 opcode)
6186{
6187 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006188 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006189 struct mgmt_rp_remove_advertising rp;
6190
6191 BT_DBG("status %d", status);
6192
6193 hci_dev_lock(hdev);
6194
6195 /* A failure status here only means that we failed to disable
6196 * advertising. Otherwise, the advertising instance has been removed,
6197 * so report success.
6198 */
6199 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6200 if (!cmd)
6201 goto unlock;
6202
Florian Grandel01948332015-06-18 03:16:48 +02006203 cp = cmd->param;
6204 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006205
6206 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6207 &rp, sizeof(rp));
6208 mgmt_pending_remove(cmd);
6209
6210unlock:
6211 hci_dev_unlock(hdev);
6212}
6213
6214static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6215 void *data, u16 data_len)
6216{
6217 struct mgmt_cp_remove_advertising *cp = data;
6218 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006219 struct mgmt_pending_cmd *cmd;
6220 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006221 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006222
6223 BT_DBG("%s", hdev->name);
6224
Arman Ugurayda9293352015-03-23 15:57:13 -07006225 hci_dev_lock(hdev);
6226
Johan Hedberg952497b2015-06-18 21:05:31 +03006227 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006228 err = mgmt_cmd_status(sk, hdev->id,
6229 MGMT_OP_REMOVE_ADVERTISING,
6230 MGMT_STATUS_INVALID_PARAMS);
6231 goto unlock;
6232 }
6233
Arman Ugurayda9293352015-03-23 15:57:13 -07006234 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6235 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6236 pending_find(MGMT_OP_SET_LE, hdev)) {
6237 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6238 MGMT_STATUS_BUSY);
6239 goto unlock;
6240 }
6241
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006242 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006243 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6244 MGMT_STATUS_INVALID_PARAMS);
6245 goto unlock;
6246 }
6247
Florian Grandel01948332015-06-18 03:16:48 +02006248 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006249
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006250 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006251
Florian Grandel01948332015-06-18 03:16:48 +02006252 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006253 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006254
Florian Grandel01948332015-06-18 03:16:48 +02006255 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6256 * flag is set or the device isn't powered then we have no HCI
6257 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006258 */
Florian Grandel01948332015-06-18 03:16:48 +02006259 if (skb_queue_empty(&req.cmd_q) ||
6260 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006261 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006262 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006263 err = mgmt_cmd_complete(sk, hdev->id,
6264 MGMT_OP_REMOVE_ADVERTISING,
6265 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6266 goto unlock;
6267 }
6268
6269 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6270 data_len);
6271 if (!cmd) {
6272 err = -ENOMEM;
6273 goto unlock;
6274 }
6275
Arman Ugurayda9293352015-03-23 15:57:13 -07006276 err = hci_req_run(&req, remove_advertising_complete);
6277 if (err < 0)
6278 mgmt_pending_remove(cmd);
6279
6280unlock:
6281 hci_dev_unlock(hdev);
6282
6283 return err;
6284}
6285
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006286static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6287{
6288 u8 max_len = HCI_MAX_AD_LENGTH;
6289
6290 if (is_adv_data) {
6291 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6292 MGMT_ADV_FLAG_LIMITED_DISCOV |
6293 MGMT_ADV_FLAG_MANAGED_FLAGS))
6294 max_len -= 3;
6295
6296 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6297 max_len -= 3;
6298 }
6299
6300 return max_len;
6301}
6302
6303static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6304 void *data, u16 data_len)
6305{
6306 struct mgmt_cp_get_adv_size_info *cp = data;
6307 struct mgmt_rp_get_adv_size_info rp;
6308 u32 flags, supported_flags;
6309 int err;
6310
6311 BT_DBG("%s", hdev->name);
6312
6313 if (!lmp_le_capable(hdev))
6314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6315 MGMT_STATUS_REJECTED);
6316
6317 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6318 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6319 MGMT_STATUS_INVALID_PARAMS);
6320
6321 flags = __le32_to_cpu(cp->flags);
6322
6323 /* The current implementation only supports a subset of the specified
6324 * flags.
6325 */
6326 supported_flags = get_supported_adv_flags(hdev);
6327 if (flags & ~supported_flags)
6328 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6329 MGMT_STATUS_INVALID_PARAMS);
6330
6331 rp.instance = cp->instance;
6332 rp.flags = cp->flags;
6333 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6334 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6335
6336 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6337 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6338
6339 return err;
6340}
6341
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006342static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006343 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006344 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006345 HCI_MGMT_NO_HDEV |
6346 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006347 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006348 HCI_MGMT_NO_HDEV |
6349 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006350 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006351 HCI_MGMT_NO_HDEV |
6352 HCI_MGMT_UNTRUSTED },
6353 { read_controller_info, MGMT_READ_INFO_SIZE,
6354 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006355 { set_powered, MGMT_SETTING_SIZE },
6356 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6357 { set_connectable, MGMT_SETTING_SIZE },
6358 { set_fast_connectable, MGMT_SETTING_SIZE },
6359 { set_bondable, MGMT_SETTING_SIZE },
6360 { set_link_security, MGMT_SETTING_SIZE },
6361 { set_ssp, MGMT_SETTING_SIZE },
6362 { set_hs, MGMT_SETTING_SIZE },
6363 { set_le, MGMT_SETTING_SIZE },
6364 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6365 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6366 { add_uuid, MGMT_ADD_UUID_SIZE },
6367 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006368 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6369 HCI_MGMT_VAR_LEN },
6370 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6371 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006372 { disconnect, MGMT_DISCONNECT_SIZE },
6373 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6374 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6375 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6376 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6377 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6378 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6379 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6380 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6381 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6382 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6383 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006384 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6385 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6386 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006387 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6388 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6389 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6390 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6391 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6392 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6393 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6394 { set_advertising, MGMT_SETTING_SIZE },
6395 { set_bredr, MGMT_SETTING_SIZE },
6396 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6397 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6398 { set_secure_conn, MGMT_SETTING_SIZE },
6399 { set_debug_keys, MGMT_SETTING_SIZE },
6400 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006401 { load_irks, MGMT_LOAD_IRKS_SIZE,
6402 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006403 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6404 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6405 { add_device, MGMT_ADD_DEVICE_SIZE },
6406 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006407 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6408 HCI_MGMT_VAR_LEN },
6409 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006410 HCI_MGMT_NO_HDEV |
6411 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006412 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006413 HCI_MGMT_UNCONFIGURED |
6414 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006415 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6416 HCI_MGMT_UNCONFIGURED },
6417 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6418 HCI_MGMT_UNCONFIGURED },
6419 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6420 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006421 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006422 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006423 HCI_MGMT_NO_HDEV |
6424 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006425 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006426 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6427 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006428 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006429 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006430 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006431 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6432 HCI_MGMT_UNTRUSTED },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006433};
6434
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006435void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006436{
Marcel Holtmannced85542015-03-14 19:27:56 -07006437 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006438
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006439 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6440 return;
6441
Marcel Holtmannf9207332015-03-14 19:27:55 -07006442 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006443 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006444 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6445 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6446 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006447 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006448 } else {
6449 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6450 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006451 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006452 }
6453 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006454 case HCI_AMP:
6455 ev.type = 0x02;
6456 break;
6457 default:
6458 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006459 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006460
6461 ev.bus = hdev->bus;
6462
6463 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6464 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006465}
6466
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006467void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006468{
Marcel Holtmannced85542015-03-14 19:27:56 -07006469 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006470 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006471
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006472 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6473 return;
6474
Marcel Holtmannf9207332015-03-14 19:27:55 -07006475 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006476 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006477 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006478
Marcel Holtmannf9207332015-03-14 19:27:55 -07006479 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6480 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6481 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006482 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006483 } else {
6484 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6485 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006486 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006487 }
6488 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006489 case HCI_AMP:
6490 ev.type = 0x02;
6491 break;
6492 default:
6493 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006494 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006495
6496 ev.bus = hdev->bus;
6497
6498 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6499 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006500}
6501
Andre Guedes6046dc32014-02-26 20:21:51 -03006502/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006503static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006504{
6505 struct hci_conn_params *p;
6506
6507 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006508 /* Needed for AUTO_OFF case where might not "really"
6509 * have been powered off.
6510 */
6511 list_del_init(&p->action);
6512
6513 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006514 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006515 case HCI_AUTO_CONN_ALWAYS:
6516 list_add(&p->action, &hdev->pend_le_conns);
6517 break;
6518 case HCI_AUTO_CONN_REPORT:
6519 list_add(&p->action, &hdev->pend_le_reports);
6520 break;
6521 default:
6522 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006523 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006524 }
6525}
6526
Johan Hedberg2ff13892015-11-25 16:15:44 +02006527void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006528{
6529 struct cmd_lookup match = { NULL, hdev };
6530
Johan Hedberg2ff13892015-11-25 16:15:44 +02006531 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006532
Johan Hedberg2ff13892015-11-25 16:15:44 +02006533 hci_dev_lock(hdev);
6534
6535 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006536 restart_le_actions(hdev);
6537 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006538 }
6539
Johan Hedberg229ab392013-03-15 17:06:53 -05006540 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6541
6542 new_settings(hdev, match.sk);
6543
Johan Hedberg229ab392013-03-15 17:06:53 -05006544 if (match.sk)
6545 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006546
6547 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006548}
6549
Johan Hedberg2ff13892015-11-25 16:15:44 +02006550void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006551{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006552 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006553 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006554
Johan Hedberg229ab392013-03-15 17:06:53 -05006555 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006556
6557 /* If the power off is because of hdev unregistration let
6558 * use the appropriate INVALID_INDEX status. Otherwise use
6559 * NOT_POWERED. We cover both scenarios here since later in
6560 * mgmt_index_removed() any hci_conn callbacks will have already
6561 * been triggered, potentially causing misleading DISCONNECTED
6562 * status responses.
6563 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006564 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006565 status = MGMT_STATUS_INVALID_INDEX;
6566 else
6567 status = MGMT_STATUS_NOT_POWERED;
6568
6569 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006570
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006571 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02006572 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6573 zero_cod, sizeof(zero_cod),
6574 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006575 ext_info_changed(hdev, NULL);
6576 }
Johan Hedberg229ab392013-03-15 17:06:53 -05006577
Johan Hedberg2ff13892015-11-25 16:15:44 +02006578 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006579
6580 if (match.sk)
6581 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006582}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006583
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006584void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006585{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006586 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006587 u8 status;
6588
Johan Hedberg333ae952015-03-17 13:48:47 +02006589 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006590 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006591 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006592
6593 if (err == -ERFKILL)
6594 status = MGMT_STATUS_RFKILLED;
6595 else
6596 status = MGMT_STATUS_FAILED;
6597
Johan Hedberga69e8372015-03-06 21:08:53 +02006598 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006599
6600 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006601}
6602
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006603void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6604 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006605{
Johan Hedberg86742e12011-11-07 23:13:38 +02006606 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006607
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006608 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006609
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006610 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006611 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006612 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006613 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006614 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006615 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006616
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006617 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006618}
Johan Hedbergf7520542011-01-20 12:34:39 +02006619
Johan Hedbergd7b25452014-05-23 13:19:53 +03006620static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6621{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006622 switch (ltk->type) {
6623 case SMP_LTK:
6624 case SMP_LTK_SLAVE:
6625 if (ltk->authenticated)
6626 return MGMT_LTK_AUTHENTICATED;
6627 return MGMT_LTK_UNAUTHENTICATED;
6628 case SMP_LTK_P256:
6629 if (ltk->authenticated)
6630 return MGMT_LTK_P256_AUTH;
6631 return MGMT_LTK_P256_UNAUTH;
6632 case SMP_LTK_P256_DEBUG:
6633 return MGMT_LTK_P256_DEBUG;
6634 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006635
6636 return MGMT_LTK_UNAUTHENTICATED;
6637}
6638
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006639void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006640{
6641 struct mgmt_ev_new_long_term_key ev;
6642
6643 memset(&ev, 0, sizeof(ev));
6644
Marcel Holtmann5192d302014-02-19 17:11:58 -08006645 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006646 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006647 * to store long term keys. Their addresses will change the
6648 * next time around.
6649 *
6650 * Only when a remote device provides an identity address
6651 * make sure the long term key is stored. If the remote
6652 * identity is known, the long term keys are internally
6653 * mapped to the identity address. So allow static random
6654 * and public addresses here.
6655 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006656 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6657 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6658 ev.store_hint = 0x00;
6659 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006660 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006661
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006662 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006663 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006664 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006665 ev.key.enc_size = key->enc_size;
6666 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006667 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006668
Johan Hedberg2ceba532014-06-16 19:25:16 +03006669 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006670 ev.key.master = 1;
6671
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006672 /* Make sure we copy only the significant bytes based on the
6673 * encryption key size, and set the rest of the value to zeroes.
6674 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006675 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006676 memset(ev.key.val + key->enc_size, 0,
6677 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006678
Marcel Holtmann083368f2013-10-15 14:26:29 -07006679 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006680}
6681
Johan Hedbergcad20c22015-10-12 13:36:19 +02006682void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006683{
6684 struct mgmt_ev_new_irk ev;
6685
6686 memset(&ev, 0, sizeof(ev));
6687
Johan Hedbergcad20c22015-10-12 13:36:19 +02006688 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006689
Johan Hedberg95fbac82014-02-19 15:18:31 +02006690 bacpy(&ev.rpa, &irk->rpa);
6691 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6692 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6693 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6694
6695 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6696}
6697
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006698void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6699 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006700{
6701 struct mgmt_ev_new_csrk ev;
6702
6703 memset(&ev, 0, sizeof(ev));
6704
6705 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006706 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006707 * to store signature resolving keys. Their addresses will change
6708 * the next time around.
6709 *
6710 * Only when a remote device provides an identity address
6711 * make sure the signature resolving key is stored. So allow
6712 * static random and public addresses here.
6713 */
6714 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6715 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6716 ev.store_hint = 0x00;
6717 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006718 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006719
6720 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6721 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006722 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006723 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6724
6725 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6726}
6727
Andre Guedesffb5a8272014-07-01 18:10:11 -03006728void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006729 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6730 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006731{
6732 struct mgmt_ev_new_conn_param ev;
6733
Johan Hedbergc103aea2014-07-02 17:37:34 +03006734 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6735 return;
6736
Andre Guedesffb5a8272014-07-01 18:10:11 -03006737 memset(&ev, 0, sizeof(ev));
6738 bacpy(&ev.addr.bdaddr, bdaddr);
6739 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006740 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006741 ev.min_interval = cpu_to_le16(min_interval);
6742 ev.max_interval = cpu_to_le16(max_interval);
6743 ev.latency = cpu_to_le16(latency);
6744 ev.timeout = cpu_to_le16(timeout);
6745
6746 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6747}
6748
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006749void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6750 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006751{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006752 char buf[512];
6753 struct mgmt_ev_device_connected *ev = (void *) buf;
6754 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006755
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006756 bacpy(&ev->addr.bdaddr, &conn->dst);
6757 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006758
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006759 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006760
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006761 /* We must ensure that the EIR Data fields are ordered and
6762 * unique. Keep it simple for now and avoid the problem by not
6763 * adding any BR/EDR data to the LE adv.
6764 */
6765 if (conn->le_adv_data_len > 0) {
6766 memcpy(&ev->eir[eir_len],
6767 conn->le_adv_data, conn->le_adv_data_len);
6768 eir_len = conn->le_adv_data_len;
6769 } else {
6770 if (name_len > 0)
6771 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6772 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006773
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006774 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006775 eir_len = eir_append_data(ev->eir, eir_len,
6776 EIR_CLASS_OF_DEV,
6777 conn->dev_class, 3);
6778 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006779
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006780 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006781
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006782 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6783 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006784}
6785
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006786static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006787{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006788 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006789
Johan Hedbergf5818c22014-12-05 13:36:02 +02006790 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006791
6792 *sk = cmd->sk;
6793 sock_hold(*sk);
6794
Johan Hedberga664b5b2011-02-19 12:06:02 -03006795 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006796}
6797
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006798static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006799{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006800 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006801 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006802
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006803 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6804
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006805 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006806 mgmt_pending_remove(cmd);
6807}
6808
Johan Hedberg84c61d92014-08-01 11:13:30 +03006809bool mgmt_powering_down(struct hci_dev *hdev)
6810{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006811 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006812 struct mgmt_mode *cp;
6813
Johan Hedberg333ae952015-03-17 13:48:47 +02006814 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006815 if (!cmd)
6816 return false;
6817
6818 cp = cmd->param;
6819 if (!cp->val)
6820 return true;
6821
6822 return false;
6823}
6824
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006825void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006826 u8 link_type, u8 addr_type, u8 reason,
6827 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006828{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006829 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006830 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006831
Johan Hedberg84c61d92014-08-01 11:13:30 +03006832 /* The connection is still in hci_conn_hash so test for 1
6833 * instead of 0 to know if this is the last one.
6834 */
6835 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6836 cancel_delayed_work(&hdev->power_off);
6837 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006838 }
6839
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006840 if (!mgmt_connected)
6841 return;
6842
Andre Guedes57eb7762013-10-30 19:01:41 -03006843 if (link_type != ACL_LINK && link_type != LE_LINK)
6844 return;
6845
Johan Hedberg744cf192011-11-08 20:40:14 +02006846 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006847
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006848 bacpy(&ev.addr.bdaddr, bdaddr);
6849 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6850 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006851
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006852 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006853
6854 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006855 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006856
Johan Hedberg124f6e32012-02-09 13:50:12 +02006857 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006858 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006859}
6860
Marcel Holtmann78929242013-10-06 23:55:47 -07006861void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6862 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006863{
Andre Guedes3655bba2013-10-30 19:01:40 -03006864 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6865 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006866 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006867
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006868 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6869 hdev);
6870
Johan Hedberg333ae952015-03-17 13:48:47 +02006871 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006872 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006873 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006874
Andre Guedes3655bba2013-10-30 19:01:40 -03006875 cp = cmd->param;
6876
6877 if (bacmp(bdaddr, &cp->addr.bdaddr))
6878 return;
6879
6880 if (cp->addr.type != bdaddr_type)
6881 return;
6882
Johan Hedbergf5818c22014-12-05 13:36:02 +02006883 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006884 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006885}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006886
Marcel Holtmann445608d2013-10-06 23:55:48 -07006887void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6888 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006889{
6890 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006891
Johan Hedberg84c61d92014-08-01 11:13:30 +03006892 /* The connection is still in hci_conn_hash so test for 1
6893 * instead of 0 to know if this is the last one.
6894 */
6895 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6896 cancel_delayed_work(&hdev->power_off);
6897 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006898 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006899
Johan Hedberg4c659c32011-11-07 23:13:39 +02006900 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006901 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006902 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006903
Marcel Holtmann445608d2013-10-06 23:55:48 -07006904 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006905}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006906
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006907void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006908{
6909 struct mgmt_ev_pin_code_request ev;
6910
Johan Hedbergd8457692012-02-17 14:24:57 +02006911 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006912 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006913 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006914
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006915 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006916}
6917
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006918void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6919 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006920{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006921 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006922
Johan Hedberg333ae952015-03-17 13:48:47 +02006923 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006924 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006925 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006926
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006927 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006928 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006929}
6930
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006931void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6932 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006933{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006934 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006935
Johan Hedberg333ae952015-03-17 13:48:47 +02006936 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006937 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006938 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006939
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006940 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006941 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006942}
Johan Hedberga5c29682011-02-19 12:05:57 -03006943
Johan Hedberg744cf192011-11-08 20:40:14 +02006944int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006945 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006946 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006947{
6948 struct mgmt_ev_user_confirm_request ev;
6949
Johan Hedberg744cf192011-11-08 20:40:14 +02006950 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006951
Johan Hedberg272d90d2012-02-09 15:26:12 +02006952 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006953 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006954 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006955 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006956
Johan Hedberg744cf192011-11-08 20:40:14 +02006957 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006958 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006959}
6960
Johan Hedberg272d90d2012-02-09 15:26:12 +02006961int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006962 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08006963{
6964 struct mgmt_ev_user_passkey_request ev;
6965
6966 BT_DBG("%s", hdev->name);
6967
Johan Hedberg272d90d2012-02-09 15:26:12 +02006968 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006969 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08006970
6971 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006972 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08006973}
6974
Brian Gix0df4c182011-11-16 13:53:13 -08006975static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006976 u8 link_type, u8 addr_type, u8 status,
6977 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03006978{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006979 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03006980
Johan Hedberg333ae952015-03-17 13:48:47 +02006981 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03006982 if (!cmd)
6983 return -ENOENT;
6984
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006985 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006986 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03006987
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006988 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03006989}
6990
Johan Hedberg744cf192011-11-08 20:40:14 +02006991int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006992 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006993{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006994 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006995 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006996}
6997
Johan Hedberg272d90d2012-02-09 15:26:12 +02006998int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006999 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007000{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007001 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007002 status,
7003 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007004}
Johan Hedberg2a611692011-02-19 12:06:00 -03007005
Brian Gix604086b2011-11-23 08:28:33 -08007006int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007007 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007008{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007009 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007010 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007011}
7012
Johan Hedberg272d90d2012-02-09 15:26:12 +02007013int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007014 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007015{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007016 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007017 status,
7018 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007019}
7020
Johan Hedberg92a25252012-09-06 18:39:26 +03007021int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7022 u8 link_type, u8 addr_type, u32 passkey,
7023 u8 entered)
7024{
7025 struct mgmt_ev_passkey_notify ev;
7026
7027 BT_DBG("%s", hdev->name);
7028
7029 bacpy(&ev.addr.bdaddr, bdaddr);
7030 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7031 ev.passkey = __cpu_to_le32(passkey);
7032 ev.entered = entered;
7033
7034 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7035}
7036
Johan Hedberge1e930f2014-09-08 17:09:49 -07007037void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007038{
7039 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007040 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007041 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007042
Johan Hedberge1e930f2014-09-08 17:09:49 -07007043 bacpy(&ev.addr.bdaddr, &conn->dst);
7044 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7045 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007046
Johan Hedberge1e930f2014-09-08 17:09:49 -07007047 cmd = find_pairing(conn);
7048
7049 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7050 cmd ? cmd->sk : NULL);
7051
Johan Hedberga511b352014-12-11 21:45:45 +02007052 if (cmd) {
7053 cmd->cmd_complete(cmd, status);
7054 mgmt_pending_remove(cmd);
7055 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007056}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007057
Marcel Holtmann464996a2013-10-15 14:26:24 -07007058void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007059{
7060 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007061 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007062
7063 if (status) {
7064 u8 mgmt_err = mgmt_status(status);
7065 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007066 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007067 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007068 }
7069
Marcel Holtmann464996a2013-10-15 14:26:24 -07007070 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007071 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007072 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007073 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007074
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007075 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007076 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007077
Johan Hedberg47990ea2012-02-22 11:58:37 +02007078 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007079 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007080
7081 if (match.sk)
7082 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007083}
7084
Johan Hedberg890ea892013-03-15 17:06:52 -05007085static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007086{
Johan Hedberg890ea892013-03-15 17:06:52 -05007087 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007088 struct hci_cp_write_eir cp;
7089
Johan Hedberg976eb202012-10-24 21:12:01 +03007090 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007091 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007092
Johan Hedbergc80da272012-02-22 15:38:48 +02007093 memset(hdev->eir, 0, sizeof(hdev->eir));
7094
Johan Hedbergcacaf522012-02-21 00:52:42 +02007095 memset(&cp, 0, sizeof(cp));
7096
Johan Hedberg890ea892013-03-15 17:06:52 -05007097 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007098}
7099
Marcel Holtmann3e248562013-10-15 14:26:25 -07007100void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007101{
7102 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007103 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007104 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007105
7106 if (status) {
7107 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007108
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007109 if (enable && hci_dev_test_and_clear_flag(hdev,
7110 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007111 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007112 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007113 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007114
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007115 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7116 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007117 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007118 }
7119
7120 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007121 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007122 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007123 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007124 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007125 changed = hci_dev_test_and_clear_flag(hdev,
7126 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007127 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007128 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007129 }
7130
7131 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7132
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007133 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007134 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007135
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007136 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007137 sock_put(match.sk);
7138
Johan Hedberg890ea892013-03-15 17:06:52 -05007139 hci_req_init(&req, hdev);
7140
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007141 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7142 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007143 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7144 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007145 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007146 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007147 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007148 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007149
7150 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007151}
7152
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007153static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007154{
7155 struct cmd_lookup *match = data;
7156
Johan Hedberg90e70452012-02-23 23:09:40 +02007157 if (match->sk == NULL) {
7158 match->sk = cmd->sk;
7159 sock_hold(match->sk);
7160 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007161}
7162
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007163void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7164 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007165{
Johan Hedberg90e70452012-02-23 23:09:40 +02007166 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007167
Johan Hedberg92da6092013-03-15 17:06:55 -05007168 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7169 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7170 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007171
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007172 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007173 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7174 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007175 ext_info_changed(hdev, NULL);
7176 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007177
7178 if (match.sk)
7179 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007180}
7181
Marcel Holtmann7667da32013-10-15 14:26:27 -07007182void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007183{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007184 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007185 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007186
Johan Hedberg13928972013-03-15 17:07:00 -05007187 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007188 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007189
7190 memset(&ev, 0, sizeof(ev));
7191 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007192 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007193
Johan Hedberg333ae952015-03-17 13:48:47 +02007194 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007195 if (!cmd) {
7196 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007197
Johan Hedberg13928972013-03-15 17:07:00 -05007198 /* If this is a HCI command related to powering on the
7199 * HCI dev don't send any mgmt signals.
7200 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007201 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007202 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007203 }
7204
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007205 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7206 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007207 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007208}
Szymon Jancc35938b2011-03-22 13:12:21 +01007209
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007210static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7211{
7212 int i;
7213
7214 for (i = 0; i < uuid_count; i++) {
7215 if (!memcmp(uuid, uuids[i], 16))
7216 return true;
7217 }
7218
7219 return false;
7220}
7221
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007222static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7223{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007224 u16 parsed = 0;
7225
7226 while (parsed < eir_len) {
7227 u8 field_len = eir[0];
7228 u8 uuid[16];
7229 int i;
7230
7231 if (field_len == 0)
7232 break;
7233
7234 if (eir_len - parsed < field_len + 1)
7235 break;
7236
7237 switch (eir[1]) {
7238 case EIR_UUID16_ALL:
7239 case EIR_UUID16_SOME:
7240 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007241 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007242 uuid[13] = eir[i + 3];
7243 uuid[12] = eir[i + 2];
7244 if (has_uuid(uuid, uuid_count, uuids))
7245 return true;
7246 }
7247 break;
7248 case EIR_UUID32_ALL:
7249 case EIR_UUID32_SOME:
7250 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007251 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007252 uuid[15] = eir[i + 5];
7253 uuid[14] = eir[i + 4];
7254 uuid[13] = eir[i + 3];
7255 uuid[12] = eir[i + 2];
7256 if (has_uuid(uuid, uuid_count, uuids))
7257 return true;
7258 }
7259 break;
7260 case EIR_UUID128_ALL:
7261 case EIR_UUID128_SOME:
7262 for (i = 0; i + 17 <= field_len; i += 16) {
7263 memcpy(uuid, eir + i + 2, 16);
7264 if (has_uuid(uuid, uuid_count, uuids))
7265 return true;
7266 }
7267 break;
7268 }
7269
7270 parsed += field_len + 1;
7271 eir += field_len + 1;
7272 }
7273
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007274 return false;
7275}
7276
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007277static void restart_le_scan(struct hci_dev *hdev)
7278{
7279 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007280 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007281 return;
7282
7283 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7284 hdev->discovery.scan_start +
7285 hdev->discovery.scan_duration))
7286 return;
7287
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007288 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007289 DISCOV_LE_RESTART_DELAY);
7290}
7291
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007292static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7293 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7294{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007295 /* If a RSSI threshold has been specified, and
7296 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7297 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7298 * is set, let it through for further processing, as we might need to
7299 * restart the scan.
7300 *
7301 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7302 * the results are also dropped.
7303 */
7304 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7305 (rssi == HCI_RSSI_INVALID ||
7306 (rssi < hdev->discovery.rssi &&
7307 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7308 return false;
7309
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007310 if (hdev->discovery.uuid_count != 0) {
7311 /* If a list of UUIDs is provided in filter, results with no
7312 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007313 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007314 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7315 hdev->discovery.uuids) &&
7316 !eir_has_uuids(scan_rsp, scan_rsp_len,
7317 hdev->discovery.uuid_count,
7318 hdev->discovery.uuids))
7319 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007320 }
7321
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007322 /* If duplicate filtering does not report RSSI changes, then restart
7323 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007324 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007325 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7326 restart_le_scan(hdev);
7327
7328 /* Validate RSSI value against the RSSI threshold once more. */
7329 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7330 rssi < hdev->discovery.rssi)
7331 return false;
7332 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007333
7334 return true;
7335}
7336
Marcel Holtmann901801b2013-10-06 23:55:51 -07007337void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007338 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7339 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007340{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007341 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007342 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007343 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007344
Johan Hedberg75ce2082014-07-02 22:42:01 +03007345 /* Don't send events for a non-kernel initiated discovery. With
7346 * LE one exception is if we have pend_le_reports > 0 in which
7347 * case we're doing passive scanning and want these events.
7348 */
7349 if (!hci_discovery_active(hdev)) {
7350 if (link_type == ACL_LINK)
7351 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007352 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007353 return;
7354 }
Andre Guedes12602d02013-04-30 15:29:40 -03007355
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007356 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007357 /* We are using service discovery */
7358 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7359 scan_rsp_len))
7360 return;
7361 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007362
Johan Hedberg78b781c2016-01-05 13:19:32 +02007363 if (hdev->discovery.limited) {
7364 /* Check for limited discoverable bit */
7365 if (dev_class) {
7366 if (!(dev_class[1] & 0x20))
7367 return;
7368 } else {
7369 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7370 if (!flags || !(flags[0] & LE_AD_LIMITED))
7371 return;
7372 }
7373 }
7374
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007375 /* Make sure that the buffer is big enough. The 5 extra bytes
7376 * are for the potential CoD field.
7377 */
7378 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007379 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007380
Johan Hedberg1dc06092012-01-15 21:01:23 +02007381 memset(buf, 0, sizeof(buf));
7382
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007383 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7384 * RSSI value was reported as 0 when not available. This behavior
7385 * is kept when using device discovery. This is required for full
7386 * backwards compatibility with the API.
7387 *
7388 * However when using service discovery, the value 127 will be
7389 * returned when the RSSI is not available.
7390 */
Szymon Janc91200e92015-01-22 16:57:05 +01007391 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7392 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007393 rssi = 0;
7394
Johan Hedberg841c5642014-07-07 12:45:54 +03007395 bacpy(&ev->addr.bdaddr, bdaddr);
7396 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007397 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007398 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007399
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007400 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007401 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007402 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007403
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007404 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7405 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007406 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007407 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007408
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007409 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007410 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007411 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007412
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007413 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7414 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007415
Marcel Holtmann901801b2013-10-06 23:55:51 -07007416 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007417}
Johan Hedberga88a9652011-03-30 13:18:12 +03007418
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007419void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7420 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007421{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007422 struct mgmt_ev_device_found *ev;
7423 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7424 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007425
Johan Hedbergb644ba32012-01-17 21:48:47 +02007426 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007427
Johan Hedbergb644ba32012-01-17 21:48:47 +02007428 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007429
Johan Hedbergb644ba32012-01-17 21:48:47 +02007430 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007431 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007432 ev->rssi = rssi;
7433
7434 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007435 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007436
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007437 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007438
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007439 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007440}
Johan Hedberg314b2382011-04-27 10:29:57 -04007441
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007442void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007443{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007444 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007445
Andre Guedes343fb142011-11-22 17:14:19 -03007446 BT_DBG("%s discovering %u", hdev->name, discovering);
7447
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007448 memset(&ev, 0, sizeof(ev));
7449 ev.type = hdev->discovery.type;
7450 ev.discovering = discovering;
7451
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007452 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007453}
Antti Julku5e762442011-08-25 16:48:02 +03007454
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007455static struct hci_mgmt_chan chan = {
7456 .channel = HCI_CHANNEL_CONTROL,
7457 .handler_count = ARRAY_SIZE(mgmt_handlers),
7458 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007459 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007460};
7461
7462int mgmt_init(void)
7463{
7464 return hci_mgmt_chan_register(&chan);
7465}
7466
7467void mgmt_exit(void)
7468{
7469 hci_mgmt_chan_unregister(&chan);
7470}