blob: 69001f415efaf8fd12dc27741386106a6ba543e7 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Johan Hedberg87510972016-07-13 10:57:18 +030041#define MGMT_REVISION 13
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200106 MGMT_OP_START_LIMITED_DISCOVERY,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200107 MGMT_OP_READ_EXT_INFO,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200108};
109
110static const u16 mgmt_events[] = {
111 MGMT_EV_CONTROLLER_ERROR,
112 MGMT_EV_INDEX_ADDED,
113 MGMT_EV_INDEX_REMOVED,
114 MGMT_EV_NEW_SETTINGS,
115 MGMT_EV_CLASS_OF_DEV_CHANGED,
116 MGMT_EV_LOCAL_NAME_CHANGED,
117 MGMT_EV_NEW_LINK_KEY,
118 MGMT_EV_NEW_LONG_TERM_KEY,
119 MGMT_EV_DEVICE_CONNECTED,
120 MGMT_EV_DEVICE_DISCONNECTED,
121 MGMT_EV_CONNECT_FAILED,
122 MGMT_EV_PIN_CODE_REQUEST,
123 MGMT_EV_USER_CONFIRM_REQUEST,
124 MGMT_EV_USER_PASSKEY_REQUEST,
125 MGMT_EV_AUTH_FAILED,
126 MGMT_EV_DEVICE_FOUND,
127 MGMT_EV_DISCOVERING,
128 MGMT_EV_DEVICE_BLOCKED,
129 MGMT_EV_DEVICE_UNBLOCKED,
130 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300131 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800132 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700133 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200134 MGMT_EV_DEVICE_ADDED,
135 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300136 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200137 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200138 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200139 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700140 MGMT_EV_EXT_INDEX_ADDED,
141 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700142 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700143 MGMT_EV_ADVERTISING_ADDED,
144 MGMT_EV_ADVERTISING_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200145 MGMT_EV_EXT_INFO_CHANGED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200146};
147
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700148static const u16 mgmt_untrusted_commands[] = {
149 MGMT_OP_READ_INDEX_LIST,
150 MGMT_OP_READ_INFO,
151 MGMT_OP_READ_UNCONF_INDEX_LIST,
152 MGMT_OP_READ_CONFIG_INFO,
153 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200154 MGMT_OP_READ_EXT_INFO,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700155};
156
157static const u16 mgmt_untrusted_events[] = {
158 MGMT_EV_INDEX_ADDED,
159 MGMT_EV_INDEX_REMOVED,
160 MGMT_EV_NEW_SETTINGS,
161 MGMT_EV_CLASS_OF_DEV_CHANGED,
162 MGMT_EV_LOCAL_NAME_CHANGED,
163 MGMT_EV_UNCONF_INDEX_ADDED,
164 MGMT_EV_UNCONF_INDEX_REMOVED,
165 MGMT_EV_NEW_CONFIG_OPTIONS,
166 MGMT_EV_EXT_INDEX_ADDED,
167 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200168 MGMT_EV_EXT_INFO_CHANGED,
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700169};
170
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800171#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200172
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200173#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
174 "\x00\x00\x00\x00\x00\x00\x00\x00"
175
Johan Hedbergca69b792011-11-11 18:10:00 +0200176/* HCI to MGMT error code conversion table */
177static u8 mgmt_status_table[] = {
178 MGMT_STATUS_SUCCESS,
179 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
180 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
181 MGMT_STATUS_FAILED, /* Hardware Failure */
182 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200184 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200185 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
186 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
187 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
188 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
189 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
190 MGMT_STATUS_BUSY, /* Command Disallowed */
191 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
192 MGMT_STATUS_REJECTED, /* Rejected Security */
193 MGMT_STATUS_REJECTED, /* Rejected Personal */
194 MGMT_STATUS_TIMEOUT, /* Host Timeout */
195 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
196 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
197 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
198 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
199 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
200 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
201 MGMT_STATUS_BUSY, /* Repeated Attempts */
202 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
203 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
204 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
205 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
206 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
207 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
208 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
209 MGMT_STATUS_FAILED, /* Unspecified Error */
210 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
211 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
212 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
213 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
214 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
215 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
216 MGMT_STATUS_FAILED, /* Unit Link Key Used */
217 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
218 MGMT_STATUS_TIMEOUT, /* Instant Passed */
219 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
220 MGMT_STATUS_FAILED, /* Transaction Collision */
221 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
222 MGMT_STATUS_REJECTED, /* QoS Rejected */
223 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
224 MGMT_STATUS_REJECTED, /* Insufficient Security */
225 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
226 MGMT_STATUS_BUSY, /* Role Switch Pending */
227 MGMT_STATUS_FAILED, /* Slot Violation */
228 MGMT_STATUS_FAILED, /* Role Switch Failed */
229 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
230 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
231 MGMT_STATUS_BUSY, /* Host Busy Pairing */
232 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
233 MGMT_STATUS_BUSY, /* Controller Busy */
234 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
235 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
236 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
237 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
238 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
239};
240
241static u8 mgmt_status(u8 hci_status)
242{
243 if (hci_status < ARRAY_SIZE(mgmt_status_table))
244 return mgmt_status_table[hci_status];
245
246 return MGMT_STATUS_FAILED;
247}
248
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700249static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
250 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700251{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700252 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
253 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700254}
255
Marcel Holtmann72000df2015-03-16 16:11:21 -0700256static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
257 u16 len, int flag, struct sock *skip_sk)
258{
259 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
260 flag, skip_sk);
261}
262
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200263static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
264 struct sock *skip_sk)
265{
266 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700267 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200268}
269
Johan Hedberg85813a72015-10-21 18:02:59 +0300270static u8 le_addr_type(u8 mgmt_addr_type)
271{
272 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
273 return ADDR_LE_DEV_PUBLIC;
274 else
275 return ADDR_LE_DEV_RANDOM;
276}
277
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200278void mgmt_fill_version_info(void *ver)
279{
280 struct mgmt_rp_read_version *rp = ver;
281
282 rp->version = MGMT_VERSION;
283 rp->revision = cpu_to_le16(MGMT_REVISION);
284}
285
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300286static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
287 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200288{
289 struct mgmt_rp_read_version rp;
290
291 BT_DBG("sock %p", sk);
292
Marcel Holtmann03c979c2016-08-27 20:23:39 +0200293 mgmt_fill_version_info(&rp);
Johan Hedberga38528f2011-01-22 06:46:43 +0200294
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200295 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
296 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200297}
298
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300299static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
300 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200301{
302 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700303 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 size_t rp_size;
305 int i, err;
306
307 BT_DBG("sock %p", sk);
308
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700309 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
310 num_commands = ARRAY_SIZE(mgmt_commands);
311 num_events = ARRAY_SIZE(mgmt_events);
312 } else {
313 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
314 num_events = ARRAY_SIZE(mgmt_untrusted_events);
315 }
316
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200317 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
318
319 rp = kmalloc(rp_size, GFP_KERNEL);
320 if (!rp)
321 return -ENOMEM;
322
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700323 rp->num_commands = cpu_to_le16(num_commands);
324 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200325
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700326 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
327 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200328
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700329 for (i = 0; i < num_commands; i++, opcode++)
330 put_unaligned_le16(mgmt_commands[i], opcode);
331
332 for (i = 0; i < num_events; i++, opcode++)
333 put_unaligned_le16(mgmt_events[i], opcode);
334 } else {
335 __le16 *opcode = rp->opcodes;
336
337 for (i = 0; i < num_commands; i++, opcode++)
338 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
339
340 for (i = 0; i < num_events; i++, opcode++)
341 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
342 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200343
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200344 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
345 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200346 kfree(rp);
347
348 return err;
349}
350
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300351static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
352 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200355 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200356 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300358 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
360 BT_DBG("sock %p", sk);
361
362 read_lock(&hci_dev_list_lock);
363
364 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300365 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200366 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700367 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700368 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200369 }
370
Johan Hedberga38528f2011-01-22 06:46:43 +0200371 rp_len = sizeof(*rp) + (2 * count);
372 rp = kmalloc(rp_len, GFP_ATOMIC);
373 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100374 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200375 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100376 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200377
Johan Hedberg476e44c2012-10-19 20:10:46 +0300378 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200379 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700380 if (hci_dev_test_flag(d, HCI_SETUP) ||
381 hci_dev_test_flag(d, HCI_CONFIG) ||
382 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383 continue;
384
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200385 /* Devices marked as raw-only are neither configured
386 * nor unconfigured controllers.
387 */
388 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700389 continue;
390
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200391 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700392 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700393 rp->index[count++] = cpu_to_le16(d->id);
394 BT_DBG("Added hci%u", d->id);
395 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 }
397
Johan Hedberg476e44c2012-10-19 20:10:46 +0300398 rp->num_controllers = cpu_to_le16(count);
399 rp_len = sizeof(*rp) + (2 * count);
400
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200401 read_unlock(&hci_dev_list_lock);
402
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200403 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
404 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200405
Johan Hedberga38528f2011-01-22 06:46:43 +0200406 kfree(rp);
407
408 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200409}
410
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200411static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
412 void *data, u16 data_len)
413{
414 struct mgmt_rp_read_unconf_index_list *rp;
415 struct hci_dev *d;
416 size_t rp_len;
417 u16 count;
418 int err;
419
420 BT_DBG("sock %p", sk);
421
422 read_lock(&hci_dev_list_lock);
423
424 count = 0;
425 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200426 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700427 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200428 count++;
429 }
430
431 rp_len = sizeof(*rp) + (2 * count);
432 rp = kmalloc(rp_len, GFP_ATOMIC);
433 if (!rp) {
434 read_unlock(&hci_dev_list_lock);
435 return -ENOMEM;
436 }
437
438 count = 0;
439 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700440 if (hci_dev_test_flag(d, HCI_SETUP) ||
441 hci_dev_test_flag(d, HCI_CONFIG) ||
442 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200443 continue;
444
445 /* Devices marked as raw-only are neither configured
446 * nor unconfigured controllers.
447 */
448 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
449 continue;
450
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200451 if (d->dev_type == HCI_PRIMARY &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700452 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200453 rp->index[count++] = cpu_to_le16(d->id);
454 BT_DBG("Added hci%u", d->id);
455 }
456 }
457
458 rp->num_controllers = cpu_to_le16(count);
459 rp_len = sizeof(*rp) + (2 * count);
460
461 read_unlock(&hci_dev_list_lock);
462
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200463 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
464 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200465
466 kfree(rp);
467
468 return err;
469}
470
Marcel Holtmann96f14742015-03-14 19:27:57 -0700471static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
472 void *data, u16 data_len)
473{
474 struct mgmt_rp_read_ext_index_list *rp;
475 struct hci_dev *d;
476 size_t rp_len;
477 u16 count;
478 int err;
479
480 BT_DBG("sock %p", sk);
481
482 read_lock(&hci_dev_list_lock);
483
484 count = 0;
485 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200486 if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
Marcel Holtmann96f14742015-03-14 19:27:57 -0700487 count++;
488 }
489
490 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
491 rp = kmalloc(rp_len, GFP_ATOMIC);
492 if (!rp) {
493 read_unlock(&hci_dev_list_lock);
494 return -ENOMEM;
495 }
496
497 count = 0;
498 list_for_each_entry(d, &hci_dev_list, list) {
499 if (hci_dev_test_flag(d, HCI_SETUP) ||
500 hci_dev_test_flag(d, HCI_CONFIG) ||
501 hci_dev_test_flag(d, HCI_USER_CHANNEL))
502 continue;
503
504 /* Devices marked as raw-only are neither configured
505 * nor unconfigured controllers.
506 */
507 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
508 continue;
509
Marcel Holtmannca8bee52016-07-05 14:30:14 +0200510 if (d->dev_type == HCI_PRIMARY) {
Marcel Holtmann96f14742015-03-14 19:27:57 -0700511 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
512 rp->entry[count].type = 0x01;
513 else
514 rp->entry[count].type = 0x00;
515 } else if (d->dev_type == HCI_AMP) {
516 rp->entry[count].type = 0x02;
517 } else {
518 continue;
519 }
520
521 rp->entry[count].bus = d->bus;
522 rp->entry[count++].index = cpu_to_le16(d->id);
523 BT_DBG("Added hci%u", d->id);
524 }
525
526 rp->num_controllers = cpu_to_le16(count);
527 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
528
529 read_unlock(&hci_dev_list_lock);
530
531 /* If this command is called at least once, then all the
532 * default index and unconfigured index events are disabled
533 * and from now on only extended index events are used.
534 */
535 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
536 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
537 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
538
539 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
540 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
541
542 kfree(rp);
543
544 return err;
545}
546
Marcel Holtmanndbece372014-07-04 18:11:55 +0200547static bool is_configured(struct hci_dev *hdev)
548{
549 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700550 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200551 return false;
552
553 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
554 !bacmp(&hdev->public_addr, BDADDR_ANY))
555 return false;
556
557 return true;
558}
559
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200560static __le32 get_missing_options(struct hci_dev *hdev)
561{
562 u32 options = 0;
563
Marcel Holtmanndbece372014-07-04 18:11:55 +0200564 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700565 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200566 options |= MGMT_OPTION_EXTERNAL_CONFIG;
567
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200568 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
569 !bacmp(&hdev->public_addr, BDADDR_ANY))
570 options |= MGMT_OPTION_PUBLIC_ADDRESS;
571
572 return cpu_to_le32(options);
573}
574
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200575static int new_options(struct hci_dev *hdev, struct sock *skip)
576{
577 __le32 options = get_missing_options(hdev);
578
Marcel Holtmann5504c3a2016-08-29 06:19:46 +0200579 return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
580 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200581}
582
Marcel Holtmanndbece372014-07-04 18:11:55 +0200583static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
584{
585 __le32 options = get_missing_options(hdev);
586
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200587 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
588 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200589}
590
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200591static int read_config_info(struct sock *sk, struct hci_dev *hdev,
592 void *data, u16 data_len)
593{
594 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200595 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200596
597 BT_DBG("sock %p %s", sk, hdev->name);
598
599 hci_dev_lock(hdev);
600
601 memset(&rp, 0, sizeof(rp));
602 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200603
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200604 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
605 options |= MGMT_OPTION_EXTERNAL_CONFIG;
606
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200607 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200608 options |= MGMT_OPTION_PUBLIC_ADDRESS;
609
610 rp.supported_options = cpu_to_le32(options);
611 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200612
613 hci_dev_unlock(hdev);
614
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200615 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
616 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200617}
618
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200619static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200620{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200621 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200622
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200623 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300624 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800625 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300626 settings |= MGMT_SETTING_CONNECTABLE;
627 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200628
Andre Guedesed3fa312012-07-24 15:03:46 -0300629 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500630 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
631 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200632 settings |= MGMT_SETTING_BREDR;
633 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700634
635 if (lmp_ssp_capable(hdev)) {
636 settings |= MGMT_SETTING_SSP;
637 settings |= MGMT_SETTING_HS;
638 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800639
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800640 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800641 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700642 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100643
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300644 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200645 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300646 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300647 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200648 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800649 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300650 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200651
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200652 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
653 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200654 settings |= MGMT_SETTING_CONFIGURATION;
655
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200656 return settings;
657}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200658
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200659static u32 get_current_settings(struct hci_dev *hdev)
660{
661 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200662
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200663 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100664 settings |= MGMT_SETTING_POWERED;
665
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700666 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200667 settings |= MGMT_SETTING_CONNECTABLE;
668
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700669 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500670 settings |= MGMT_SETTING_FAST_CONNECTABLE;
671
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700672 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200673 settings |= MGMT_SETTING_DISCOVERABLE;
674
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700675 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300676 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200677
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700678 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200679 settings |= MGMT_SETTING_BREDR;
680
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700681 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200682 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200683
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700684 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200685 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200686
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700687 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200688 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200689
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700690 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200691 settings |= MGMT_SETTING_HS;
692
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700693 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300694 settings |= MGMT_SETTING_ADVERTISING;
695
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700696 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800697 settings |= MGMT_SETTING_SECURE_CONN;
698
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700699 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800700 settings |= MGMT_SETTING_DEBUG_KEYS;
701
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700702 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200703 settings |= MGMT_SETTING_PRIVACY;
704
Marcel Holtmann93690c22015-03-06 10:11:21 -0800705 /* The current setting for static address has two purposes. The
706 * first is to indicate if the static address will be used and
707 * the second is to indicate if it is actually set.
708 *
709 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e982015-03-25 18:32:13 -0700710 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800711 * address is actually used decides if the flag is set or not.
712 *
713 * For single mode LE only controllers and dual-mode controllers
714 * with BR/EDR disabled, the existence of the static address will
715 * be evaluated.
716 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700717 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700718 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800719 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
720 if (bacmp(&hdev->static_addr, BDADDR_ANY))
721 settings |= MGMT_SETTING_STATIC_ADDRESS;
722 }
723
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200724 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200725}
726
Johan Hedberg333ae952015-03-17 13:48:47 +0200727static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
728{
729 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
730}
731
Johan Hedberg333ae952015-03-17 13:48:47 +0200732static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
733 struct hci_dev *hdev,
734 const void *data)
735{
736 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
737}
738
Johan Hedbergf2252572015-11-18 12:49:20 +0200739u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300740{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200741 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300742
743 /* If there's a pending mgmt command the flags will not yet have
744 * their final values, so check for this first.
745 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200746 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300747 if (cmd) {
748 struct mgmt_mode *cp = cmd->param;
749 if (cp->val == 0x01)
750 return LE_AD_GENERAL;
751 else if (cp->val == 0x02)
752 return LE_AD_LIMITED;
753 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700754 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300755 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700756 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300757 return LE_AD_GENERAL;
758 }
759
760 return 0;
761}
762
Johan Hedbergf2252572015-11-18 12:49:20 +0200763bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700764{
765 struct mgmt_pending_cmd *cmd;
766
767 /* If there's a pending mgmt command the flag will not yet have
768 * it's final value, so check for this first.
769 */
770 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
771 if (cmd) {
772 struct mgmt_mode *cp = cmd->param;
773
774 return cp->val;
775 }
776
777 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
778}
779
Johan Hedberg7d785252011-12-15 00:47:39 +0200780static void service_cache_off(struct work_struct *work)
781{
782 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300783 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500784 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200785
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700786 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200787 return;
788
Johan Hedberg890ea892013-03-15 17:06:52 -0500789 hci_req_init(&req, hdev);
790
Johan Hedberg7d785252011-12-15 00:47:39 +0200791 hci_dev_lock(hdev);
792
Johan Hedbergb1a89172015-11-25 16:15:42 +0200793 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200794 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200795
796 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500797
798 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200799}
800
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200801static void rpa_expired(struct work_struct *work)
802{
803 struct hci_dev *hdev = container_of(work, struct hci_dev,
804 rpa_expired.work);
805 struct hci_request req;
806
807 BT_DBG("");
808
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700809 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200810
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700811 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200812 return;
813
814 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200815 * controller happens in the hci_req_enable_advertising()
816 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200817 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200818 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +0200819 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200820 hci_req_run(&req, NULL);
821}
822
Johan Hedberg6a919082012-02-28 06:17:26 +0200823static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200824{
Marcel Holtmann238be782015-03-13 02:11:06 -0700825 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200826 return;
827
Johan Hedberg4f87da82012-03-02 19:55:56 +0200828 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200829 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200830
Johan Hedberg4f87da82012-03-02 19:55:56 +0200831 /* Non-mgmt controlled devices get this bit set
832 * implicitly so that pairing works for them, however
833 * for mgmt we require user-space to explicitly enable
834 * it
835 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700836 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200837}
838
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200839static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300840 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200841{
842 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200843
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200844 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200845
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300846 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200847
Johan Hedberg03811012010-12-08 00:21:06 +0200848 memset(&rp, 0, sizeof(rp));
849
Johan Hedberg03811012010-12-08 00:21:06 +0200850 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200851
852 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200853 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200854
855 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
856 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
857
858 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200859
860 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200861 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200862
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300863 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200864
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200865 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
866 sizeof(rp));
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200867}
868
Marcel Holtmann321c6fe2016-09-01 16:46:23 +0200869static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
870 void *data, u16 data_len)
871{
872 struct mgmt_rp_read_ext_info rp;
873
874 BT_DBG("sock %p %s", sk, hdev->name);
875
876 hci_dev_lock(hdev);
877
878 memset(&rp, 0, sizeof(rp));
879
880 bacpy(&rp.bdaddr, &hdev->bdaddr);
881
882 rp.version = hdev->hci_ver;
883 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
884
885 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
886 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
887
888 rp.eir_len = cpu_to_le16(0);
889
890 hci_dev_unlock(hdev);
891
892 /* If this command is called at least once, then the events
893 * for class of device and local name changes are disabled
894 * and only the new extended controller information event
895 * is used.
896 */
897 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
898 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
899 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
900
901 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, &rp,
902 sizeof(rp));
903}
904
905static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
906{
907 struct mgmt_ev_ext_info_changed ev;
908
909 ev.eir_len = cpu_to_le16(0);
910
911 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, &ev,
912 sizeof(ev), HCI_MGMT_EXT_INFO_EVENTS, skip);
913}
914
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200915static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200916{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200917 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200918
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200919 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
920 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200921}
922
Marcel Holtmann1904a852015-01-11 13:50:44 -0800923static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200924{
925 BT_DBG("%s status 0x%02x", hdev->name, status);
926
Johan Hedberga3172b72014-02-28 09:33:44 +0200927 if (hci_conn_count(hdev) == 0) {
928 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200929 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200930 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200931}
932
Johan Hedbergf2252572015-11-18 12:49:20 +0200933void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700934{
935 struct mgmt_ev_advertising_added ev;
936
937 ev.instance = instance;
938
939 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
940}
941
Johan Hedbergf2252572015-11-18 12:49:20 +0200942void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
943 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700944{
945 struct mgmt_ev_advertising_removed ev;
946
947 ev.instance = instance;
948
949 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
950}
951
Florian Grandel7816b822015-06-18 03:16:45 +0200952static void cancel_adv_timeout(struct hci_dev *hdev)
953{
954 if (hdev->adv_instance_timeout) {
955 hdev->adv_instance_timeout = 0;
956 cancel_delayed_work(&hdev->adv_instance_expire);
957 }
958}
959
Johan Hedberg8b064a32014-02-24 14:52:22 +0200960static int clean_up_hci_state(struct hci_dev *hdev)
961{
962 struct hci_request req;
963 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300964 bool discov_stopped;
965 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200966
967 hci_req_init(&req, hdev);
968
969 if (test_bit(HCI_ISCAN, &hdev->flags) ||
970 test_bit(HCI_PSCAN, &hdev->flags)) {
971 u8 scan = 0x00;
972 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
973 }
974
Johan Hedberg37d3a1f2016-08-28 20:53:34 +0300975 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -0700976
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700977 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +0200978 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200979
Johan Hedberg2154d3f2015-11-11 08:30:45 +0200980 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200981
982 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +0300983 /* 0x15 == Terminated due to Power Off */
984 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200985 }
986
Johan Hedberg23a48092014-07-08 16:05:06 +0300987 err = hci_req_run(&req, clean_up_hci_complete);
988 if (!err && discov_stopped)
989 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
990
991 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200992}
993
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200994static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300995 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300997 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200998 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200999 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001001 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001002
Johan Hedberga7e80f22013-01-09 16:05:19 +02001003 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001004 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1005 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001006
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001007 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001008
Johan Hedberg333ae952015-03-17 13:48:47 +02001009 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001010 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1011 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001012 goto failed;
1013 }
1014
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001015 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001016 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 goto failed;
1018 }
1019
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1021 if (!cmd) {
1022 err = -ENOMEM;
1023 goto failed;
1024 }
1025
Johan Hedberg8b064a32014-02-24 14:52:22 +02001026 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001027 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001028 err = 0;
1029 } else {
1030 /* Disconnect connections, stop scans, etc */
1031 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001032 if (!err)
1033 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1034 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001035
Johan Hedberg8b064a32014-02-24 14:52:22 +02001036 /* ENODATA means there were no HCI commands queued */
1037 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001038 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001039 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1040 err = 0;
1041 }
1042 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043
1044failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046 return err;
1047}
1048
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001049static int new_settings(struct hci_dev *hdev, struct sock *skip)
1050{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001051 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001052
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02001053 return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1054 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001055}
1056
Johan Hedberg91a668b2014-07-09 13:28:26 +03001057int mgmt_new_settings(struct hci_dev *hdev)
1058{
1059 return new_settings(hdev, NULL);
1060}
1061
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001062struct cmd_lookup {
1063 struct sock *sk;
1064 struct hci_dev *hdev;
1065 u8 mgmt_status;
1066};
1067
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001068static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001069{
1070 struct cmd_lookup *match = data;
1071
1072 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1073
1074 list_del(&cmd->list);
1075
1076 if (match->sk == NULL) {
1077 match->sk = cmd->sk;
1078 sock_hold(match->sk);
1079 }
1080
1081 mgmt_pending_free(cmd);
1082}
1083
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001084static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001085{
1086 u8 *status = data;
1087
Johan Hedberga69e8372015-03-06 21:08:53 +02001088 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001089 mgmt_pending_remove(cmd);
1090}
1091
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001092static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001093{
1094 if (cmd->cmd_complete) {
1095 u8 *status = data;
1096
1097 cmd->cmd_complete(cmd, *status);
1098 mgmt_pending_remove(cmd);
1099
1100 return;
1101 }
1102
1103 cmd_status_rsp(cmd, data);
1104}
1105
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001106static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001107{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001108 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1109 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001110}
1111
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001112static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001113{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001114 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1115 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001116}
1117
Johan Hedberge6fe7982013-10-02 15:45:22 +03001118static u8 mgmt_bredr_support(struct hci_dev *hdev)
1119{
1120 if (!lmp_bredr_capable(hdev))
1121 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001122 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001123 return MGMT_STATUS_REJECTED;
1124 else
1125 return MGMT_STATUS_SUCCESS;
1126}
1127
1128static u8 mgmt_le_support(struct hci_dev *hdev)
1129{
1130 if (!lmp_le_capable(hdev))
1131 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001132 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001133 return MGMT_STATUS_REJECTED;
1134 else
1135 return MGMT_STATUS_SUCCESS;
1136}
1137
Johan Hedbergaed1a882015-11-22 17:24:44 +03001138void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001139{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001140 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001141
1142 BT_DBG("status 0x%02x", status);
1143
1144 hci_dev_lock(hdev);
1145
Johan Hedberg333ae952015-03-17 13:48:47 +02001146 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001147 if (!cmd)
1148 goto unlock;
1149
1150 if (status) {
1151 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001152 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001153 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001154 goto remove_cmd;
1155 }
1156
Johan Hedbergaed1a882015-11-22 17:24:44 +03001157 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1158 hdev->discov_timeout > 0) {
1159 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1160 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001161 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001162
1163 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001164 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001165
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001166remove_cmd:
1167 mgmt_pending_remove(cmd);
1168
1169unlock:
1170 hci_dev_unlock(hdev);
1171}
1172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001173static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001174 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001175{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001176 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001177 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001178 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001179 int err;
1180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001181 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001182
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001183 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1184 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001185 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1186 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001187
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001188 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001189 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1190 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001191
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001192 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001193
1194 /* Disabling discoverable requires that no timeout is set,
1195 * and enabling limited discoverable requires a timeout.
1196 */
1197 if ((cp->val == 0x00 && timeout > 0) ||
1198 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001199 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1200 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001201
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001202 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001203
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001204 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001205 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1206 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207 goto failed;
1208 }
1209
Johan Hedberg333ae952015-03-17 13:48:47 +02001210 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1211 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001212 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1213 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001214 goto failed;
1215 }
1216
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001217 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001218 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1219 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001220 goto failed;
1221 }
1222
1223 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001224 bool changed = false;
1225
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001226 /* Setting limited discoverable when powered off is
1227 * not a valid operation since it requires a timeout
1228 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1229 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001230 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001231 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001232 changed = true;
1233 }
1234
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001235 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001236 if (err < 0)
1237 goto failed;
1238
1239 if (changed)
1240 err = new_settings(hdev, sk);
1241
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001242 goto failed;
1243 }
1244
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001245 /* If the current mode is the same, then just update the timeout
1246 * value with the new value. And if only the timeout gets updated,
1247 * then no need for any HCI transactions.
1248 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001249 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1250 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1251 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001252 cancel_delayed_work(&hdev->discov_off);
1253 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001254
Marcel Holtmann36261542013-10-15 08:28:51 -07001255 if (cp->val && hdev->discov_timeout > 0) {
1256 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001257 queue_delayed_work(hdev->req_workqueue,
1258 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001259 }
1260
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001261 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001262 goto failed;
1263 }
1264
1265 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1266 if (!cmd) {
1267 err = -ENOMEM;
1268 goto failed;
1269 }
1270
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001271 /* Cancel any potential discoverable timeout that might be
1272 * still active and store new timeout value. The arming of
1273 * the timeout happens in the complete handler.
1274 */
1275 cancel_delayed_work(&hdev->discov_off);
1276 hdev->discov_timeout = timeout;
1277
Johan Hedbergaed1a882015-11-22 17:24:44 +03001278 if (cp->val)
1279 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1280 else
1281 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1282
Johan Hedbergb456f872013-10-19 23:38:22 +03001283 /* Limited discoverable mode */
1284 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001285 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001286 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001287 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001288
Johan Hedbergaed1a882015-11-22 17:24:44 +03001289 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1290 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001291
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001292failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001293 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001294 return err;
1295}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001296
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001297void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001298{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001299 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001300
1301 BT_DBG("status 0x%02x", status);
1302
1303 hci_dev_lock(hdev);
1304
Johan Hedberg333ae952015-03-17 13:48:47 +02001305 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001306 if (!cmd)
1307 goto unlock;
1308
Johan Hedberg37438c12013-10-14 16:20:05 +03001309 if (status) {
1310 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001311 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001312 goto remove_cmd;
1313 }
1314
Johan Hedberg2b76f452013-03-15 17:07:04 -05001315 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001316 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001317
Johan Hedberg37438c12013-10-14 16:20:05 +03001318remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001319 mgmt_pending_remove(cmd);
1320
1321unlock:
1322 hci_dev_unlock(hdev);
1323}
1324
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001325static int set_connectable_update_settings(struct hci_dev *hdev,
1326 struct sock *sk, u8 val)
1327{
1328 bool changed = false;
1329 int err;
1330
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001331 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001332 changed = true;
1333
1334 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001335 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001336 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001337 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1338 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001339 }
1340
1341 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1342 if (err < 0)
1343 return err;
1344
Johan Hedberg562064e2014-07-08 16:35:34 +03001345 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001346 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001347 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001348 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001349 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001350
1351 return 0;
1352}
1353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001354static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001355 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001356{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001357 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001358 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001359 int err;
1360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001361 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001362
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001363 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1364 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001365 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1366 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001367
Johan Hedberga7e80f22013-01-09 16:05:19 +02001368 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001369 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1370 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001371
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001372 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001373
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001374 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001375 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001376 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001377 }
1378
Johan Hedberg333ae952015-03-17 13:48:47 +02001379 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1380 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001381 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1382 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001383 goto failed;
1384 }
1385
Johan Hedberg73f22f62010-12-29 16:00:25 +02001386 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1387 if (!cmd) {
1388 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001389 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001390 }
1391
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001392 if (cp->val) {
1393 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1394 } else {
1395 if (hdev->discov_timeout > 0)
1396 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001397
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001398 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1399 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1400 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001401 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001402
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001403 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1404 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001405
1406failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001407 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001408 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001409}
1410
Johan Hedbergb2939472014-07-30 09:22:23 +03001411static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001412 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001413{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001414 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001415 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001416 int err;
1417
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001418 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001419
Johan Hedberga7e80f22013-01-09 16:05:19 +02001420 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001421 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1422 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001423
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001424 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001425
1426 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001427 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001428 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001429 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001430
Johan Hedbergb2939472014-07-30 09:22:23 +03001431 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001432 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001433 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001434
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001435 if (changed) {
1436 /* In limited privacy mode the change of bondable mode
1437 * may affect the local advertising address.
1438 */
1439 if (hdev_is_powered(hdev) &&
1440 hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
1441 hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1442 hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
1443 queue_work(hdev->req_workqueue,
1444 &hdev->discoverable_update);
1445
Marcel Holtmann55594352013-10-06 16:11:57 -07001446 err = new_settings(hdev, sk);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02001447 }
Johan Hedberg053f0212011-01-26 13:07:10 +02001448
Marcel Holtmann55594352013-10-06 16:11:57 -07001449unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001450 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001451 return err;
1452}
1453
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001454static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1455 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001456{
1457 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001458 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001459 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001460 int err;
1461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001463
Johan Hedberge6fe7982013-10-02 15:45:22 +03001464 status = mgmt_bredr_support(hdev);
1465 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001466 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1467 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001468
Johan Hedberga7e80f22013-01-09 16:05:19 +02001469 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001470 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1471 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001472
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001473 hci_dev_lock(hdev);
1474
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001475 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001476 bool changed = false;
1477
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001478 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001479 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001480 changed = true;
1481 }
1482
1483 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1484 if (err < 0)
1485 goto failed;
1486
1487 if (changed)
1488 err = new_settings(hdev, sk);
1489
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001490 goto failed;
1491 }
1492
Johan Hedberg333ae952015-03-17 13:48:47 +02001493 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001494 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1495 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001496 goto failed;
1497 }
1498
1499 val = !!cp->val;
1500
1501 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1502 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1503 goto failed;
1504 }
1505
1506 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1507 if (!cmd) {
1508 err = -ENOMEM;
1509 goto failed;
1510 }
1511
1512 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1513 if (err < 0) {
1514 mgmt_pending_remove(cmd);
1515 goto failed;
1516 }
1517
1518failed:
1519 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001520 return err;
1521}
1522
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001523static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001524{
1525 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001526 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001527 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001528 int err;
1529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001530 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001531
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001532 status = mgmt_bredr_support(hdev);
1533 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001534 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001535
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001536 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001537 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1538 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001539
Johan Hedberga7e80f22013-01-09 16:05:19 +02001540 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001541 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1542 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001543
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001544 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001545
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001546 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001547 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001548
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001549 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001550 changed = !hci_dev_test_and_set_flag(hdev,
1551 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001552 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001553 changed = hci_dev_test_and_clear_flag(hdev,
1554 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001555 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001556 changed = hci_dev_test_and_clear_flag(hdev,
1557 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001558 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001559 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001560 }
1561
1562 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1563 if (err < 0)
1564 goto failed;
1565
1566 if (changed)
1567 err = new_settings(hdev, sk);
1568
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001569 goto failed;
1570 }
1571
Johan Hedberg333ae952015-03-17 13:48:47 +02001572 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001573 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1574 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001575 goto failed;
1576 }
1577
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001578 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001579 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1580 goto failed;
1581 }
1582
1583 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1584 if (!cmd) {
1585 err = -ENOMEM;
1586 goto failed;
1587 }
1588
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001589 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001590 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1591 sizeof(cp->val), &cp->val);
1592
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001593 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001594 if (err < 0) {
1595 mgmt_pending_remove(cmd);
1596 goto failed;
1597 }
1598
1599failed:
1600 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001601 return err;
1602}
1603
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001604static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001605{
1606 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001607 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001608 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001609 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001610
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001611 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001612
Johan Hedberge6fe7982013-10-02 15:45:22 +03001613 status = mgmt_bredr_support(hdev);
1614 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001615 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001616
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001617 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001618 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1619 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001620
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001621 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001622 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1623 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001624
Johan Hedberga7e80f22013-01-09 16:05:19 +02001625 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001626 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1627 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001628
Marcel Holtmannee392692013-10-01 22:59:23 -07001629 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001630
Johan Hedberg333ae952015-03-17 13:48:47 +02001631 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001632 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1633 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001634 goto unlock;
1635 }
1636
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001637 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001638 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001639 } else {
1640 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001641 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1642 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001643 goto unlock;
1644 }
1645
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001646 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001647 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001648
1649 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1650 if (err < 0)
1651 goto unlock;
1652
1653 if (changed)
1654 err = new_settings(hdev, sk);
1655
1656unlock:
1657 hci_dev_unlock(hdev);
1658 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001659}
1660
Marcel Holtmann1904a852015-01-11 13:50:44 -08001661static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001662{
1663 struct cmd_lookup match = { NULL, hdev };
1664
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301665 hci_dev_lock(hdev);
1666
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001667 if (status) {
1668 u8 mgmt_err = mgmt_status(status);
1669
1670 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1671 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301672 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001673 }
1674
1675 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1676
1677 new_settings(hdev, match.sk);
1678
1679 if (match.sk)
1680 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001681
1682 /* Make sure the controller has a good default for
1683 * advertising data. Restrict the update to when LE
1684 * has actually been enabled. During power on, the
1685 * update in powered_update_hci will take care of it.
1686 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001687 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001688 struct hci_request req;
1689
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001690 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001691 __hci_req_update_adv_data(&req, 0x00);
1692 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001693 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001694 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001695 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301696
1697unlock:
1698 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001699}
1700
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001701static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001702{
1703 struct mgmt_mode *cp = data;
1704 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001705 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001706 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001707 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001708 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001709
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001710 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001711
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001712 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001713 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1714 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001715
Johan Hedberga7e80f22013-01-09 16:05:19 +02001716 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001717 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1718 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001719
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001720 /* Bluetooth single mode LE only controllers or dual-mode
1721 * controllers configured as LE only devices, do not allow
1722 * switching LE off. These have either LE enabled explicitly
1723 * or BR/EDR has been previously switched off.
1724 *
1725 * When trying to enable an already enabled LE, then gracefully
1726 * send a positive response. Trying to disable it however will
1727 * result into rejection.
1728 */
1729 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1730 if (cp->val == 0x01)
1731 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1732
Johan Hedberga69e8372015-03-06 21:08:53 +02001733 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1734 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001735 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001736
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001737 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001738
1739 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001740 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001741
Florian Grandel847818d2015-06-18 03:16:46 +02001742 if (!val)
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03001743 hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001744
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001745 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001746 bool changed = false;
1747
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001748 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001749 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001750 changed = true;
1751 }
1752
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001753 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001754 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001755 changed = true;
1756 }
1757
Johan Hedberg06199cf2012-02-22 16:37:11 +02001758 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1759 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001760 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001761
1762 if (changed)
1763 err = new_settings(hdev, sk);
1764
Johan Hedberg1de028c2012-02-29 19:55:35 -08001765 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001766 }
1767
Johan Hedberg333ae952015-03-17 13:48:47 +02001768 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1769 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001770 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1771 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001772 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001773 }
1774
1775 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1776 if (!cmd) {
1777 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001778 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001779 }
1780
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001781 hci_req_init(&req, hdev);
1782
Johan Hedberg06199cf2012-02-22 16:37:11 +02001783 memset(&hci_cp, 0, sizeof(hci_cp));
1784
1785 if (val) {
1786 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001787 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001788 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001789 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001790 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001791 }
1792
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001793 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1794 &hci_cp);
1795
1796 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301797 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001798 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001799
Johan Hedberg1de028c2012-02-29 19:55:35 -08001800unlock:
1801 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001802 return err;
1803}
1804
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001805/* This is a helper function to test for pending mgmt commands that can
1806 * cause CoD or EIR HCI commands. We can only allow one such pending
1807 * mgmt command at a time since otherwise we cannot easily track what
1808 * the current values are, will be, and based on that calculate if a new
1809 * HCI command needs to be sent and if yes with what value.
1810 */
1811static bool pending_eir_or_class(struct hci_dev *hdev)
1812{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001813 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001814
1815 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1816 switch (cmd->opcode) {
1817 case MGMT_OP_ADD_UUID:
1818 case MGMT_OP_REMOVE_UUID:
1819 case MGMT_OP_SET_DEV_CLASS:
1820 case MGMT_OP_SET_POWERED:
1821 return true;
1822 }
1823 }
1824
1825 return false;
1826}
1827
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001828static const u8 bluetooth_base_uuid[] = {
1829 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1830 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1831};
1832
1833static u8 get_uuid_size(const u8 *uuid)
1834{
1835 u32 val;
1836
1837 if (memcmp(uuid, bluetooth_base_uuid, 12))
1838 return 128;
1839
1840 val = get_unaligned_le32(&uuid[12]);
1841 if (val > 0xffff)
1842 return 32;
1843
1844 return 16;
1845}
1846
Johan Hedberg92da6092013-03-15 17:06:55 -05001847static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1848{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001849 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001850
1851 hci_dev_lock(hdev);
1852
Johan Hedberg333ae952015-03-17 13:48:47 +02001853 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001854 if (!cmd)
1855 goto unlock;
1856
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001857 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1858 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001859
1860 mgmt_pending_remove(cmd);
1861
1862unlock:
1863 hci_dev_unlock(hdev);
1864}
1865
Marcel Holtmann1904a852015-01-11 13:50:44 -08001866static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001867{
1868 BT_DBG("status 0x%02x", status);
1869
1870 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1871}
1872
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001873static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001874{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001875 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001876 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001877 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001878 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001879 int err;
1880
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001882
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001883 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001884
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001885 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001886 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1887 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001888 goto failed;
1889 }
1890
Andre Guedes92c4c202012-06-07 19:05:44 -03001891 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001892 if (!uuid) {
1893 err = -ENOMEM;
1894 goto failed;
1895 }
1896
1897 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001898 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001899 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001900
Johan Hedbergde66aa62013-01-27 00:31:27 +02001901 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001902
Johan Hedberg890ea892013-03-15 17:06:52 -05001903 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001904
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001905 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001906 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001907
Johan Hedberg92da6092013-03-15 17:06:55 -05001908 err = hci_req_run(&req, add_uuid_complete);
1909 if (err < 0) {
1910 if (err != -ENODATA)
1911 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001912
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001913 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1914 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001915 goto failed;
1916 }
1917
1918 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001919 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001920 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001921 goto failed;
1922 }
1923
1924 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001925
1926failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001927 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001928 return err;
1929}
1930
Johan Hedberg24b78d02012-02-23 23:24:30 +02001931static bool enable_service_cache(struct hci_dev *hdev)
1932{
1933 if (!hdev_is_powered(hdev))
1934 return false;
1935
Marcel Holtmann238be782015-03-13 02:11:06 -07001936 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001937 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1938 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001939 return true;
1940 }
1941
1942 return false;
1943}
1944
Marcel Holtmann1904a852015-01-11 13:50:44 -08001945static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001946{
1947 BT_DBG("status 0x%02x", status);
1948
1949 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1950}
1951
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001952static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001953 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001954{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001955 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001956 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001957 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001958 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 -05001959 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001960 int err, found;
1961
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001962 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001963
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001964 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001965
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001966 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001967 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1968 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001969 goto unlock;
1970 }
1971
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001972 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02001973 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001974
Johan Hedberg24b78d02012-02-23 23:24:30 +02001975 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001976 err = mgmt_cmd_complete(sk, hdev->id,
1977 MGMT_OP_REMOVE_UUID,
1978 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001979 goto unlock;
1980 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001981
Johan Hedberg9246a862012-02-23 21:33:16 +02001982 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001983 }
1984
1985 found = 0;
1986
Johan Hedberg056341c2013-01-27 00:31:30 +02001987 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001988 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1989 continue;
1990
1991 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001992 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001993 found++;
1994 }
1995
1996 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001997 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1998 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001999 goto unlock;
2000 }
2001
Johan Hedberg9246a862012-02-23 21:33:16 +02002002update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002003 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002004
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002005 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002006 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002007
Johan Hedberg92da6092013-03-15 17:06:55 -05002008 err = hci_req_run(&req, remove_uuid_complete);
2009 if (err < 0) {
2010 if (err != -ENODATA)
2011 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002012
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002013 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2014 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002015 goto unlock;
2016 }
2017
2018 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002019 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002020 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002021 goto unlock;
2022 }
2023
2024 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002025
2026unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002027 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002028 return err;
2029}
2030
Marcel Holtmann1904a852015-01-11 13:50:44 -08002031static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002032{
2033 BT_DBG("status 0x%02x", status);
2034
2035 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2036}
2037
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002038static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002039 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002040{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002041 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002042 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002043 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002044 int err;
2045
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002046 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002047
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002048 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002049 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2050 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002051
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002052 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002053
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002054 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002055 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2056 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002057 goto unlock;
2058 }
2059
2060 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002061 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2062 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002063 goto unlock;
2064 }
2065
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002066 hdev->major_class = cp->major;
2067 hdev->minor_class = cp->minor;
2068
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002069 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002070 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2071 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002072 goto unlock;
2073 }
2074
Johan Hedberg890ea892013-03-15 17:06:52 -05002075 hci_req_init(&req, hdev);
2076
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002077 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002078 hci_dev_unlock(hdev);
2079 cancel_delayed_work_sync(&hdev->service_cache);
2080 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002081 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002082 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002083
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002084 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002085
Johan Hedberg92da6092013-03-15 17:06:55 -05002086 err = hci_req_run(&req, set_class_complete);
2087 if (err < 0) {
2088 if (err != -ENODATA)
2089 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002090
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002091 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2092 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002093 goto unlock;
2094 }
2095
2096 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002097 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002098 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002099 goto unlock;
2100 }
2101
2102 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002103
Johan Hedbergb5235a62012-02-21 14:32:24 +02002104unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002105 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002106 return err;
2107}
2108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002110 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002111{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002112 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002113 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2114 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002115 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002116 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002117 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002118
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002119 BT_DBG("request for %s", hdev->name);
2120
2121 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002122 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2123 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002124
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002125 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002126 if (key_count > max_key_count) {
2127 BT_ERR("load_link_keys: too big key_count value %u",
2128 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002129 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2130 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002131 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002132
Johan Hedberg86742e12011-11-07 23:13:38 +02002133 expected_len = sizeof(*cp) + key_count *
2134 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002135 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002136 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002137 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002138 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2139 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002140 }
2141
Johan Hedberg4ae143012013-01-20 14:27:13 +02002142 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002143 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2144 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002146 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002147 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002148
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002149 for (i = 0; i < key_count; i++) {
2150 struct mgmt_link_key_info *key = &cp->keys[i];
2151
Marcel Holtmann8e991132014-01-10 02:07:25 -08002152 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002153 return mgmt_cmd_status(sk, hdev->id,
2154 MGMT_OP_LOAD_LINK_KEYS,
2155 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002156 }
2157
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002158 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002159
2160 hci_link_keys_clear(hdev);
2161
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002162 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002163 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002164 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002165 changed = hci_dev_test_and_clear_flag(hdev,
2166 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002167
2168 if (changed)
2169 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002170
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002171 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002172 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002173
Johan Hedberg58e92932014-06-24 14:00:26 +03002174 /* Always ignore debug keys and require a new pairing if
2175 * the user wants to use them.
2176 */
2177 if (key->type == HCI_LK_DEBUG_COMBINATION)
2178 continue;
2179
Johan Hedberg7652ff62014-06-24 13:15:49 +03002180 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2181 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002182 }
2183
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002184 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002185
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002186 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002187
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002188 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002189}
2190
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002191static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002192 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002193{
2194 struct mgmt_ev_device_unpaired ev;
2195
2196 bacpy(&ev.addr.bdaddr, bdaddr);
2197 ev.addr.type = addr_type;
2198
2199 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002200 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002201}
2202
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002203static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002204 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002205{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002206 struct mgmt_cp_unpair_device *cp = data;
2207 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002208 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002209 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002210 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002211 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002212 int err;
2213
Johan Hedberga8a1d192011-11-10 15:54:38 +02002214 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002215 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2216 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002217
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002218 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002219 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2220 MGMT_STATUS_INVALID_PARAMS,
2221 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002222
Johan Hedberg118da702013-01-20 14:27:20 +02002223 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002224 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2225 MGMT_STATUS_INVALID_PARAMS,
2226 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002227
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002228 hci_dev_lock(hdev);
2229
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002230 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002231 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2232 MGMT_STATUS_NOT_POWERED, &rp,
2233 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002234 goto unlock;
2235 }
2236
Johan Hedberge0b2b272014-02-18 17:14:31 +02002237 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002238 /* If disconnection is requested, then look up the
2239 * connection. If the remote device is connected, it
2240 * will be later used to terminate the link.
2241 *
2242 * Setting it to NULL explicitly will cause no
2243 * termination of the link.
2244 */
2245 if (cp->disconnect)
2246 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2247 &cp->addr.bdaddr);
2248 else
2249 conn = NULL;
2250
Johan Hedberg124f6e32012-02-09 13:50:12 +02002251 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002252 if (err < 0) {
2253 err = mgmt_cmd_complete(sk, hdev->id,
2254 MGMT_OP_UNPAIR_DEVICE,
2255 MGMT_STATUS_NOT_PAIRED, &rp,
2256 sizeof(rp));
2257 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002258 }
2259
Johan Hedbergec182f02015-10-21 18:03:03 +03002260 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002261 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002262
Johan Hedbergec182f02015-10-21 18:03:03 +03002263 /* LE address type */
2264 addr_type = le_addr_type(cp->addr.type);
2265
2266 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2267
2268 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002269 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002270 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2271 MGMT_STATUS_NOT_PAIRED, &rp,
2272 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002273 goto unlock;
2274 }
2275
Johan Hedbergec182f02015-10-21 18:03:03 +03002276 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2277 if (!conn) {
2278 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2279 goto done;
2280 }
2281
Johan Hedbergc81d5552015-10-22 09:38:35 +03002282 /* Abort any ongoing SMP pairing */
2283 smp_cancel_pairing(conn);
2284
Johan Hedbergec182f02015-10-21 18:03:03 +03002285 /* Defer clearing up the connection parameters until closing to
2286 * give a chance of keeping them if a repairing happens.
2287 */
2288 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2289
Johan Hedbergfc643612015-10-22 09:38:31 +03002290 /* Disable auto-connection parameters if present */
2291 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2292 if (params) {
2293 if (params->explicit_connect)
2294 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2295 else
2296 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2297 }
2298
Johan Hedbergec182f02015-10-21 18:03:03 +03002299 /* If disconnection is not requested, then clear the connection
2300 * variable so that the link is not terminated.
2301 */
2302 if (!cp->disconnect)
2303 conn = NULL;
2304
2305done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002306 /* If the connection variable is set, then termination of the
2307 * link is requested.
2308 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002309 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002310 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2311 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002312 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002313 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002314 }
2315
Johan Hedberg124f6e32012-02-09 13:50:12 +02002316 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002317 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002318 if (!cmd) {
2319 err = -ENOMEM;
2320 goto unlock;
2321 }
2322
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002323 cmd->cmd_complete = addr_cmd_complete;
2324
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002325 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002326 if (err < 0)
2327 mgmt_pending_remove(cmd);
2328
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002329unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002330 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002331 return err;
2332}
2333
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002334static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002335 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002336{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002337 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002338 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002339 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002340 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002341 int err;
2342
2343 BT_DBG("");
2344
Johan Hedberg06a63b12013-01-20 14:27:21 +02002345 memset(&rp, 0, sizeof(rp));
2346 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2347 rp.addr.type = cp->addr.type;
2348
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002349 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002350 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2351 MGMT_STATUS_INVALID_PARAMS,
2352 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002353
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002354 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002355
2356 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002357 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2358 MGMT_STATUS_NOT_POWERED, &rp,
2359 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002360 goto failed;
2361 }
2362
Johan Hedberg333ae952015-03-17 13:48:47 +02002363 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002364 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2365 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002366 goto failed;
2367 }
2368
Andre Guedes591f47f2012-04-24 21:02:49 -03002369 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002370 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2371 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002372 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002373 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2374 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002375
Vishal Agarwalf9607272012-06-13 05:32:43 +05302376 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002377 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2378 MGMT_STATUS_NOT_CONNECTED, &rp,
2379 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002380 goto failed;
2381 }
2382
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002383 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002384 if (!cmd) {
2385 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002386 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002387 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002388
Johan Hedbergf5818c22014-12-05 13:36:02 +02002389 cmd->cmd_complete = generic_cmd_complete;
2390
Johan Hedberge3f2f922014-08-18 20:33:33 +03002391 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002392 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002393 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002394
2395failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002396 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002397 return err;
2398}
2399
Andre Guedes57c14772012-04-24 21:02:50 -03002400static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002401{
2402 switch (link_type) {
2403 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002404 switch (addr_type) {
2405 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002406 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002407
Johan Hedberg48264f02011-11-09 13:58:58 +02002408 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002409 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002410 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002411 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002412
Johan Hedberg4c659c32011-11-07 23:13:39 +02002413 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002414 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002415 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002416 }
2417}
2418
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2420 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002421{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002422 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002423 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002424 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002425 int err;
2426 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002427
2428 BT_DBG("");
2429
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002430 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002431
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002432 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002433 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2434 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002435 goto unlock;
2436 }
2437
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002438 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002439 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2440 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002441 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002442 }
2443
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002444 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002445 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002446 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002447 err = -ENOMEM;
2448 goto unlock;
2449 }
2450
Johan Hedberg2784eb42011-01-21 13:56:35 +02002451 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002452 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002453 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2454 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002455 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002456 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002457 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002458 continue;
2459 i++;
2460 }
2461
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002462 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002463
Johan Hedberg4c659c32011-11-07 23:13:39 +02002464 /* Recalculate length in case of filtered SCO connections, etc */
2465 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002466
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002467 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2468 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002469
Johan Hedberga38528f2011-01-22 06:46:43 +02002470 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002471
2472unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002473 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002474 return err;
2475}
2476
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002477static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002478 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002479{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002480 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002481 int err;
2482
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002483 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002484 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002485 if (!cmd)
2486 return -ENOMEM;
2487
Johan Hedbergd8457692012-02-17 14:24:57 +02002488 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002489 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002490 if (err < 0)
2491 mgmt_pending_remove(cmd);
2492
2493 return err;
2494}
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002498{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002499 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002500 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002501 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002502 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002503 int err;
2504
2505 BT_DBG("");
2506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002507 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002508
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002509 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002510 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2511 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002512 goto failed;
2513 }
2514
Johan Hedbergd8457692012-02-17 14:24:57 +02002515 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002516 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002517 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2518 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002519 goto failed;
2520 }
2521
2522 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002523 struct mgmt_cp_pin_code_neg_reply ncp;
2524
2525 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002526
2527 BT_ERR("PIN code is not 16 bytes long");
2528
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002529 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002530 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002531 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2532 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002533
2534 goto failed;
2535 }
2536
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002537 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002538 if (!cmd) {
2539 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002540 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002541 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002542
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002543 cmd->cmd_complete = addr_cmd_complete;
2544
Johan Hedbergd8457692012-02-17 14:24:57 +02002545 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002546 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002547 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002548
2549 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2550 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002551 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002552
2553failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002554 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002555 return err;
2556}
2557
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002558static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2559 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002560{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002561 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002562
2563 BT_DBG("");
2564
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002565 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Marcel Holtmann9db5c622016-08-29 06:31:57 +02002566 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2567 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002568
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002569 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002570
2571 hdev->io_capability = cp->io_capability;
2572
2573 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002574 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002575
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002576 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002577
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002578 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2579 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002580}
2581
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002582static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002583{
2584 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002585 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002586
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002587 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002588 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2589 continue;
2590
Johan Hedberge9a416b2011-02-19 12:05:56 -03002591 if (cmd->user_data != conn)
2592 continue;
2593
2594 return cmd;
2595 }
2596
2597 return NULL;
2598}
2599
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002600static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002601{
2602 struct mgmt_rp_pair_device rp;
2603 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002604 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002605
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002606 bacpy(&rp.addr.bdaddr, &conn->dst);
2607 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002608
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002609 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2610 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002611
2612 /* So we don't get further callbacks for this connection */
2613 conn->connect_cfm_cb = NULL;
2614 conn->security_cfm_cb = NULL;
2615 conn->disconn_cfm_cb = NULL;
2616
David Herrmann76a68ba2013-04-06 20:28:37 +02002617 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002618
2619 /* The device is paired so there is no need to remove
2620 * its connection parameters anymore.
2621 */
2622 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002623
2624 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002625
2626 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002627}
2628
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002629void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2630{
2631 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002632 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002633
2634 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002635 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002636 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002637 mgmt_pending_remove(cmd);
2638 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002639}
2640
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2642{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002643 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002644
2645 BT_DBG("status %u", status);
2646
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002647 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002648 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002649 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002650 return;
2651 }
2652
2653 cmd->cmd_complete(cmd, mgmt_status(status));
2654 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002655}
2656
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002657static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302658{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002659 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302660
2661 BT_DBG("status %u", status);
2662
2663 if (!status)
2664 return;
2665
2666 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002667 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302668 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002669 return;
2670 }
2671
2672 cmd->cmd_complete(cmd, mgmt_status(status));
2673 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302674}
2675
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002676static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002677 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002678{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002679 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002680 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002681 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002682 u8 sec_level, auth_type;
2683 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002684 int err;
2685
2686 BT_DBG("");
2687
Szymon Jancf950a30e2013-01-18 12:48:07 +01002688 memset(&rp, 0, sizeof(rp));
2689 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2690 rp.addr.type = cp->addr.type;
2691
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002692 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002693 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2694 MGMT_STATUS_INVALID_PARAMS,
2695 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002696
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002697 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002698 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2699 MGMT_STATUS_INVALID_PARAMS,
2700 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002701
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002702 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002703
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002704 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002705 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2706 MGMT_STATUS_NOT_POWERED, &rp,
2707 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002708 goto unlock;
2709 }
2710
Johan Hedberg55e76b32015-03-10 22:34:40 +02002711 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2712 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2713 MGMT_STATUS_ALREADY_PAIRED, &rp,
2714 sizeof(rp));
2715 goto unlock;
2716 }
2717
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002718 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002719 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002720
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002721 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002722 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2723 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002724 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002725 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002726 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002727
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002728 /* When pairing a new device, it is expected to remember
2729 * this device for future connections. Adding the connection
2730 * parameter information ahead of time allows tracking
2731 * of the slave preferred values and will speed up any
2732 * further connection establishment.
2733 *
2734 * If connection parameters already exist, then they
2735 * will be kept and this function does nothing.
2736 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002737 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2738
2739 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2740 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002741
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002742 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2743 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002744 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002745 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002746
Ville Tervo30e76272011-02-22 16:10:53 -03002747 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002748 int status;
2749
2750 if (PTR_ERR(conn) == -EBUSY)
2751 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002752 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2753 status = MGMT_STATUS_NOT_SUPPORTED;
2754 else if (PTR_ERR(conn) == -ECONNREFUSED)
2755 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002756 else
2757 status = MGMT_STATUS_CONNECT_FAILED;
2758
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002759 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2760 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002761 goto unlock;
2762 }
2763
2764 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002765 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002766 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2767 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002768 goto unlock;
2769 }
2770
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002771 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002772 if (!cmd) {
2773 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002774 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002775 goto unlock;
2776 }
2777
Johan Hedberg04ab2742014-12-05 13:36:04 +02002778 cmd->cmd_complete = pairing_complete;
2779
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002780 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002781 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002782 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002783 conn->security_cfm_cb = pairing_complete_cb;
2784 conn->disconn_cfm_cb = pairing_complete_cb;
2785 } else {
2786 conn->connect_cfm_cb = le_pairing_complete_cb;
2787 conn->security_cfm_cb = le_pairing_complete_cb;
2788 conn->disconn_cfm_cb = le_pairing_complete_cb;
2789 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002790
Johan Hedberge9a416b2011-02-19 12:05:56 -03002791 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002792 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002794 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002795 hci_conn_security(conn, sec_level, auth_type, true)) {
2796 cmd->cmd_complete(cmd, 0);
2797 mgmt_pending_remove(cmd);
2798 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002799
2800 err = 0;
2801
2802unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002803 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002804 return err;
2805}
2806
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002807static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2808 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002809{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002810 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002811 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002812 struct hci_conn *conn;
2813 int err;
2814
2815 BT_DBG("");
2816
Johan Hedberg28424702012-02-02 04:02:29 +02002817 hci_dev_lock(hdev);
2818
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002819 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002820 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2821 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002822 goto unlock;
2823 }
2824
Johan Hedberg333ae952015-03-17 13:48:47 +02002825 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002826 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002827 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2828 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002829 goto unlock;
2830 }
2831
2832 conn = cmd->user_data;
2833
2834 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002835 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2836 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002837 goto unlock;
2838 }
2839
Johan Hedberga511b352014-12-11 21:45:45 +02002840 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2841 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002842
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002843 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2844 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002845unlock:
2846 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002847 return err;
2848}
2849
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002850static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002851 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002852 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002853{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002854 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002855 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002856 int err;
2857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002858 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002859
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002860 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002861 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2862 MGMT_STATUS_NOT_POWERED, addr,
2863 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002864 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002865 }
2866
Johan Hedberg1707c602013-03-15 17:07:15 -05002867 if (addr->type == BDADDR_BREDR)
2868 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002869 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002870 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2871 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002872
Johan Hedberg272d90d2012-02-09 15:26:12 +02002873 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002874 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2875 MGMT_STATUS_NOT_CONNECTED, addr,
2876 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002877 goto done;
2878 }
2879
Johan Hedberg1707c602013-03-15 17:07:15 -05002880 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002881 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002882 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002883 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2884 MGMT_STATUS_SUCCESS, addr,
2885 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002886 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002887 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2888 MGMT_STATUS_FAILED, addr,
2889 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002890
Brian Gix47c15e22011-11-16 13:53:14 -08002891 goto done;
2892 }
2893
Johan Hedberg1707c602013-03-15 17:07:15 -05002894 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002895 if (!cmd) {
2896 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002897 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002898 }
2899
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002900 cmd->cmd_complete = addr_cmd_complete;
2901
Brian Gix0df4c182011-11-16 13:53:13 -08002902 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002903 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2904 struct hci_cp_user_passkey_reply cp;
2905
Johan Hedberg1707c602013-03-15 17:07:15 -05002906 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002907 cp.passkey = passkey;
2908 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2909 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002910 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2911 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002912
Johan Hedberga664b5b2011-02-19 12:06:02 -03002913 if (err < 0)
2914 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002915
Brian Gix0df4c182011-11-16 13:53:13 -08002916done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002917 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002918 return err;
2919}
2920
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302921static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2922 void *data, u16 len)
2923{
2924 struct mgmt_cp_pin_code_neg_reply *cp = data;
2925
2926 BT_DBG("");
2927
Johan Hedberg1707c602013-03-15 17:07:15 -05002928 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302929 MGMT_OP_PIN_CODE_NEG_REPLY,
2930 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2931}
2932
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002933static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2934 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002935{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002936 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002937
2938 BT_DBG("");
2939
2940 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002941 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2942 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002943
Johan Hedberg1707c602013-03-15 17:07:15 -05002944 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002945 MGMT_OP_USER_CONFIRM_REPLY,
2946 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002947}
2948
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002949static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002950 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002951{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002952 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002953
2954 BT_DBG("");
2955
Johan Hedberg1707c602013-03-15 17:07:15 -05002956 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2958 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002959}
2960
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002961static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2962 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002963{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002964 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002965
2966 BT_DBG("");
2967
Johan Hedberg1707c602013-03-15 17:07:15 -05002968 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002969 MGMT_OP_USER_PASSKEY_REPLY,
2970 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002971}
2972
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002973static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002974 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002975{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002976 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002977
2978 BT_DBG("");
2979
Johan Hedberg1707c602013-03-15 17:07:15 -05002980 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002981 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2982 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002983}
2984
Marcel Holtmann1904a852015-01-11 13:50:44 -08002985static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05002986{
2987 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002988 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05002989
2990 BT_DBG("status 0x%02x", status);
2991
2992 hci_dev_lock(hdev);
2993
Johan Hedberg333ae952015-03-17 13:48:47 +02002994 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05002995 if (!cmd)
2996 goto unlock;
2997
2998 cp = cmd->param;
2999
3000 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003001 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3002 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003003 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003004 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3005 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003006
3007 mgmt_pending_remove(cmd);
3008
3009unlock:
3010 hci_dev_unlock(hdev);
3011}
3012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003013static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003015{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003016 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003017 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003018 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003019 int err;
3020
3021 BT_DBG("");
3022
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003023 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003024
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003025 /* If the old values are the same as the new ones just return a
3026 * direct command complete event.
3027 */
3028 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3029 !memcmp(hdev->short_name, cp->short_name,
3030 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003031 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3032 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003033 goto failed;
3034 }
3035
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003036 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003037
Johan Hedbergb5235a62012-02-21 14:32:24 +02003038 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003039 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003040
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003041 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3042 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003043 if (err < 0)
3044 goto failed;
3045
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02003046 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
3047 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02003048 ext_info_changed(hdev, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003049
Johan Hedbergb5235a62012-02-21 14:32:24 +02003050 goto failed;
3051 }
3052
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003053 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003054 if (!cmd) {
3055 err = -ENOMEM;
3056 goto failed;
3057 }
3058
Johan Hedberg13928972013-03-15 17:07:00 -05003059 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3060
Johan Hedberg890ea892013-03-15 17:06:52 -05003061 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003062
3063 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003064 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003065 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003066 }
3067
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003068 /* The name is stored in the scan response data and so
3069 * no need to udpate the advertising data here.
3070 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003071 if (lmp_le_capable(hdev))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003072 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003073
Johan Hedberg13928972013-03-15 17:07:00 -05003074 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003075 if (err < 0)
3076 mgmt_pending_remove(cmd);
3077
3078failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003079 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003080 return err;
3081}
3082
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003083static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3084 u16 opcode, struct sk_buff *skb)
3085{
3086 struct mgmt_rp_read_local_oob_data mgmt_rp;
3087 size_t rp_size = sizeof(mgmt_rp);
3088 struct mgmt_pending_cmd *cmd;
3089
3090 BT_DBG("%s status %u", hdev->name, status);
3091
3092 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3093 if (!cmd)
3094 return;
3095
3096 if (status || !skb) {
3097 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3098 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3099 goto remove;
3100 }
3101
3102 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3103
3104 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3105 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3106
3107 if (skb->len < sizeof(*rp)) {
3108 mgmt_cmd_status(cmd->sk, hdev->id,
3109 MGMT_OP_READ_LOCAL_OOB_DATA,
3110 MGMT_STATUS_FAILED);
3111 goto remove;
3112 }
3113
3114 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3115 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3116
3117 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3118 } else {
3119 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3120
3121 if (skb->len < sizeof(*rp)) {
3122 mgmt_cmd_status(cmd->sk, hdev->id,
3123 MGMT_OP_READ_LOCAL_OOB_DATA,
3124 MGMT_STATUS_FAILED);
3125 goto remove;
3126 }
3127
3128 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3129 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3130
3131 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3132 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3133 }
3134
3135 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3136 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3137
3138remove:
3139 mgmt_pending_remove(cmd);
3140}
3141
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003142static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003143 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003144{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003145 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003146 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003147 int err;
3148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003149 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003151 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003152
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003153 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003154 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3155 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003156 goto unlock;
3157 }
3158
Andre Guedes9a1a1992012-07-24 15:03:48 -03003159 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003160 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3161 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003162 goto unlock;
3163 }
3164
Johan Hedberg333ae952015-03-17 13:48:47 +02003165 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003166 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3167 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003168 goto unlock;
3169 }
3170
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003171 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003172 if (!cmd) {
3173 err = -ENOMEM;
3174 goto unlock;
3175 }
3176
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003177 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003178
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003179 if (bredr_sc_enabled(hdev))
3180 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3181 else
3182 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3183
3184 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003185 if (err < 0)
3186 mgmt_pending_remove(cmd);
3187
3188unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003189 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003190 return err;
3191}
3192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003193static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003194 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003195{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003196 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003197 int err;
3198
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003199 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003200
Johan Hedberg5d57e792015-01-23 10:10:38 +02003201 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003202 return mgmt_cmd_complete(sk, hdev->id,
3203 MGMT_OP_ADD_REMOTE_OOB_DATA,
3204 MGMT_STATUS_INVALID_PARAMS,
3205 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003207 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003208
Marcel Holtmannec109112014-01-10 02:07:30 -08003209 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3210 struct mgmt_cp_add_remote_oob_data *cp = data;
3211 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003212
Johan Hedbergc19a4952014-11-17 20:52:19 +02003213 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003214 err = mgmt_cmd_complete(sk, hdev->id,
3215 MGMT_OP_ADD_REMOTE_OOB_DATA,
3216 MGMT_STATUS_INVALID_PARAMS,
3217 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003218 goto unlock;
3219 }
3220
Marcel Holtmannec109112014-01-10 02:07:30 -08003221 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003222 cp->addr.type, cp->hash,
3223 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003224 if (err < 0)
3225 status = MGMT_STATUS_FAILED;
3226 else
3227 status = MGMT_STATUS_SUCCESS;
3228
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003229 err = mgmt_cmd_complete(sk, hdev->id,
3230 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3231 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003232 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3233 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003234 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003235 u8 status;
3236
Johan Hedberg86df9202014-10-26 20:52:27 +01003237 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003238 /* Enforce zero-valued 192-bit parameters as
3239 * long as legacy SMP OOB isn't implemented.
3240 */
3241 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3242 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003243 err = mgmt_cmd_complete(sk, hdev->id,
3244 MGMT_OP_ADD_REMOTE_OOB_DATA,
3245 MGMT_STATUS_INVALID_PARAMS,
3246 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003247 goto unlock;
3248 }
3249
Johan Hedberg86df9202014-10-26 20:52:27 +01003250 rand192 = NULL;
3251 hash192 = NULL;
3252 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003253 /* In case one of the P-192 values is set to zero,
3254 * then just disable OOB data for P-192.
3255 */
3256 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3257 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3258 rand192 = NULL;
3259 hash192 = NULL;
3260 } else {
3261 rand192 = cp->rand192;
3262 hash192 = cp->hash192;
3263 }
3264 }
3265
3266 /* In case one of the P-256 values is set to zero, then just
3267 * disable OOB data for P-256.
3268 */
3269 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3270 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3271 rand256 = NULL;
3272 hash256 = NULL;
3273 } else {
3274 rand256 = cp->rand256;
3275 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003276 }
3277
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003278 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003279 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003280 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003281 if (err < 0)
3282 status = MGMT_STATUS_FAILED;
3283 else
3284 status = MGMT_STATUS_SUCCESS;
3285
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003286 err = mgmt_cmd_complete(sk, hdev->id,
3287 MGMT_OP_ADD_REMOTE_OOB_DATA,
3288 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003289 } else {
3290 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003291 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3292 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003293 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003294
Johan Hedbergc19a4952014-11-17 20:52:19 +02003295unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003296 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003297 return err;
3298}
3299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003300static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003301 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003302{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003303 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003304 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003305 int err;
3306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003307 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003308
Johan Hedbergc19a4952014-11-17 20:52:19 +02003309 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003310 return mgmt_cmd_complete(sk, hdev->id,
3311 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3312 MGMT_STATUS_INVALID_PARAMS,
3313 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003314
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003315 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003316
Johan Hedbergeedbd582014-11-15 09:34:23 +02003317 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3318 hci_remote_oob_data_clear(hdev);
3319 status = MGMT_STATUS_SUCCESS;
3320 goto done;
3321 }
3322
Johan Hedberg6928a922014-10-26 20:46:09 +01003323 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003324 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003325 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003326 else
Szymon Janca6785be2012-12-13 15:11:21 +01003327 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003328
Johan Hedbergeedbd582014-11-15 09:34:23 +02003329done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003330 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3331 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003332
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003333 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003334 return err;
3335}
3336
Johan Hedberge68f0722015-11-11 08:30:30 +02003337void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003338{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003339 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003340
Andre Guedes7c307722013-04-30 15:29:28 -03003341 BT_DBG("status %d", status);
3342
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003343 hci_dev_lock(hdev);
3344
Johan Hedberg333ae952015-03-17 13:48:47 +02003345 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003346 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003347 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003348
Johan Hedberg78b781c2016-01-05 13:19:32 +02003349 if (!cmd)
3350 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3351
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003352 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003353 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003354 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003355 }
3356
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003357 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003358}
3359
Johan Hedberg591752a2015-11-11 08:11:24 +02003360static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3361 uint8_t *mgmt_status)
3362{
3363 switch (type) {
3364 case DISCOV_TYPE_LE:
3365 *mgmt_status = mgmt_le_support(hdev);
3366 if (*mgmt_status)
3367 return false;
3368 break;
3369 case DISCOV_TYPE_INTERLEAVED:
3370 *mgmt_status = mgmt_le_support(hdev);
3371 if (*mgmt_status)
3372 return false;
3373 /* Intentional fall-through */
3374 case DISCOV_TYPE_BREDR:
3375 *mgmt_status = mgmt_bredr_support(hdev);
3376 if (*mgmt_status)
3377 return false;
3378 break;
3379 default:
3380 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3381 return false;
3382 }
3383
3384 return true;
3385}
3386
Johan Hedberg78b781c2016-01-05 13:19:32 +02003387static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3388 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003389{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003390 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003391 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003392 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003393 int err;
3394
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003395 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003396
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003397 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003398
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003399 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003400 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003401 MGMT_STATUS_NOT_POWERED,
3402 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003403 goto failed;
3404 }
3405
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003406 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003407 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003408 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3409 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003410 goto failed;
3411 }
3412
Johan Hedberg591752a2015-11-11 08:11:24 +02003413 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003414 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3415 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003416 goto failed;
3417 }
3418
Marcel Holtmann22078802014-12-05 11:45:22 +01003419 /* Clear the discovery filter first to free any previously
3420 * allocated memory for the UUID list.
3421 */
3422 hci_discovery_filter_clear(hdev);
3423
Andre Guedes4aab14e2012-02-17 20:39:36 -03003424 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003425 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003426 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3427 hdev->discovery.limited = true;
3428 else
3429 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003430
Johan Hedberg78b781c2016-01-05 13:19:32 +02003431 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003432 if (!cmd) {
3433 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003434 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003435 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003436
Johan Hedberge68f0722015-11-11 08:30:30 +02003437 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003438
3439 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003440 queue_work(hdev->req_workqueue, &hdev->discov_update);
3441 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003442
3443failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003444 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003445 return err;
3446}
3447
Johan Hedberg78b781c2016-01-05 13:19:32 +02003448static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3449 void *data, u16 len)
3450{
3451 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3452 data, len);
3453}
3454
3455static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3456 void *data, u16 len)
3457{
3458 return start_discovery_internal(sk, hdev,
3459 MGMT_OP_START_LIMITED_DISCOVERY,
3460 data, len);
3461}
3462
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003463static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3464 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003465{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003466 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3467 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003468}
3469
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003470static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3471 void *data, u16 len)
3472{
3473 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003474 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003475 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3476 u16 uuid_count, expected_len;
3477 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003478 int err;
3479
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003480 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003481
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003482 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003483
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003484 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003485 err = mgmt_cmd_complete(sk, hdev->id,
3486 MGMT_OP_START_SERVICE_DISCOVERY,
3487 MGMT_STATUS_NOT_POWERED,
3488 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003489 goto failed;
3490 }
3491
3492 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003493 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003494 err = mgmt_cmd_complete(sk, hdev->id,
3495 MGMT_OP_START_SERVICE_DISCOVERY,
3496 MGMT_STATUS_BUSY, &cp->type,
3497 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003498 goto failed;
3499 }
3500
3501 uuid_count = __le16_to_cpu(cp->uuid_count);
3502 if (uuid_count > max_uuid_count) {
3503 BT_ERR("service_discovery: too big uuid_count value %u",
3504 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003505 err = mgmt_cmd_complete(sk, hdev->id,
3506 MGMT_OP_START_SERVICE_DISCOVERY,
3507 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3508 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003509 goto failed;
3510 }
3511
3512 expected_len = sizeof(*cp) + uuid_count * 16;
3513 if (expected_len != len) {
3514 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3515 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003516 err = mgmt_cmd_complete(sk, hdev->id,
3517 MGMT_OP_START_SERVICE_DISCOVERY,
3518 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3519 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003520 goto failed;
3521 }
3522
Johan Hedberg591752a2015-11-11 08:11:24 +02003523 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3524 err = mgmt_cmd_complete(sk, hdev->id,
3525 MGMT_OP_START_SERVICE_DISCOVERY,
3526 status, &cp->type, sizeof(cp->type));
3527 goto failed;
3528 }
3529
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003530 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003531 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003532 if (!cmd) {
3533 err = -ENOMEM;
3534 goto failed;
3535 }
3536
Johan Hedberg2922a942014-12-05 13:36:06 +02003537 cmd->cmd_complete = service_discovery_cmd_complete;
3538
Marcel Holtmann22078802014-12-05 11:45:22 +01003539 /* Clear the discovery filter first to free any previously
3540 * allocated memory for the UUID list.
3541 */
3542 hci_discovery_filter_clear(hdev);
3543
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003544 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003545 hdev->discovery.type = cp->type;
3546 hdev->discovery.rssi = cp->rssi;
3547 hdev->discovery.uuid_count = uuid_count;
3548
3549 if (uuid_count > 0) {
3550 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3551 GFP_KERNEL);
3552 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003553 err = mgmt_cmd_complete(sk, hdev->id,
3554 MGMT_OP_START_SERVICE_DISCOVERY,
3555 MGMT_STATUS_FAILED,
3556 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003557 mgmt_pending_remove(cmd);
3558 goto failed;
3559 }
3560 }
3561
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003562 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003563 queue_work(hdev->req_workqueue, &hdev->discov_update);
3564 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003565
3566failed:
3567 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003568 return err;
3569}
3570
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003571void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003572{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003573 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003574
Andre Guedes0e05bba2013-04-30 15:29:33 -03003575 BT_DBG("status %d", status);
3576
3577 hci_dev_lock(hdev);
3578
Johan Hedberg333ae952015-03-17 13:48:47 +02003579 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003580 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003581 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003582 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003583 }
3584
Andre Guedes0e05bba2013-04-30 15:29:33 -03003585 hci_dev_unlock(hdev);
3586}
3587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003588static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003589 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003590{
Johan Hedbergd9306502012-02-20 23:25:18 +02003591 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003592 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003593 int err;
3594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003595 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003597 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003598
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003599 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003600 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3601 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3602 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003603 goto unlock;
3604 }
3605
3606 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003607 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3608 MGMT_STATUS_INVALID_PARAMS,
3609 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003610 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003611 }
3612
Johan Hedberg2922a942014-12-05 13:36:06 +02003613 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003614 if (!cmd) {
3615 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003616 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003617 }
3618
Johan Hedberg2922a942014-12-05 13:36:06 +02003619 cmd->cmd_complete = generic_cmd_complete;
3620
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003621 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3622 queue_work(hdev->req_workqueue, &hdev->discov_update);
3623 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003624
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003625unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003626 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003627 return err;
3628}
3629
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003630static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003631 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003632{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003633 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003634 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003635 int err;
3636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003637 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003638
Johan Hedberg561aafb2012-01-04 13:31:59 +02003639 hci_dev_lock(hdev);
3640
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003641 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003642 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3643 MGMT_STATUS_FAILED, &cp->addr,
3644 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003645 goto failed;
3646 }
3647
Johan Hedberga198e7b2012-02-17 14:27:06 +02003648 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003649 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003650 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3651 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3652 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003653 goto failed;
3654 }
3655
3656 if (cp->name_known) {
3657 e->name_state = NAME_KNOWN;
3658 list_del(&e->list);
3659 } else {
3660 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003661 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003662 }
3663
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003664 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3665 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003666
3667failed:
3668 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003669 return err;
3670}
3671
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003672static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003673 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003674{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003675 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003676 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003677 int err;
3678
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003679 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003680
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003681 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003682 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3683 MGMT_STATUS_INVALID_PARAMS,
3684 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003685
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003686 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003687
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003688 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3689 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003690 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003691 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003692 goto done;
3693 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003694
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003695 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3696 sk);
3697 status = MGMT_STATUS_SUCCESS;
3698
3699done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003700 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3701 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003702
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003703 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003704
3705 return err;
3706}
3707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003708static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003710{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003711 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003712 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003713 int err;
3714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003715 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003716
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003717 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003718 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3719 MGMT_STATUS_INVALID_PARAMS,
3720 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003721
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003722 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003723
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003724 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3725 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003726 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003727 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003728 goto done;
3729 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003730
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003731 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3732 sk);
3733 status = MGMT_STATUS_SUCCESS;
3734
3735done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003736 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3737 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003739 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003740
3741 return err;
3742}
3743
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003744static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3745 u16 len)
3746{
3747 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003748 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003749 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003750 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003751
3752 BT_DBG("%s", hdev->name);
3753
Szymon Jancc72d4b82012-03-16 16:02:57 +01003754 source = __le16_to_cpu(cp->source);
3755
3756 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003757 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3758 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003759
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003760 hci_dev_lock(hdev);
3761
Szymon Jancc72d4b82012-03-16 16:02:57 +01003762 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003763 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3764 hdev->devid_product = __le16_to_cpu(cp->product);
3765 hdev->devid_version = __le16_to_cpu(cp->version);
3766
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003767 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3768 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003769
Johan Hedberg890ea892013-03-15 17:06:52 -05003770 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003771 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003772 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003773
3774 hci_dev_unlock(hdev);
3775
3776 return err;
3777}
3778
Arman Uguray24b4f382015-03-23 15:57:12 -07003779static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3780 u16 opcode)
3781{
3782 BT_DBG("status %d", status);
3783}
3784
Marcel Holtmann1904a852015-01-11 13:50:44 -08003785static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3786 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003787{
3788 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003789 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003790 u8 instance;
3791 struct adv_info *adv_instance;
3792 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003793
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303794 hci_dev_lock(hdev);
3795
Johan Hedberg4375f102013-09-25 13:26:10 +03003796 if (status) {
3797 u8 mgmt_err = mgmt_status(status);
3798
3799 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3800 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303801 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003802 }
3803
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003804 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003805 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003806 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003807 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003808
Johan Hedberg4375f102013-09-25 13:26:10 +03003809 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3810 &match);
3811
3812 new_settings(hdev, match.sk);
3813
3814 if (match.sk)
3815 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303816
Arman Uguray24b4f382015-03-23 15:57:12 -07003817 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003818 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003819 */
3820 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003821 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003822 goto unlock;
3823
Florian Grandel7816b822015-06-18 03:16:45 +02003824 instance = hdev->cur_adv_instance;
3825 if (!instance) {
3826 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3827 struct adv_info, list);
3828 if (!adv_instance)
3829 goto unlock;
3830
3831 instance = adv_instance->instance;
3832 }
3833
Arman Uguray24b4f382015-03-23 15:57:12 -07003834 hci_req_init(&req, hdev);
3835
Johan Hedbergf2252572015-11-18 12:49:20 +02003836 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003837
Florian Grandel7816b822015-06-18 03:16:45 +02003838 if (!err)
3839 err = hci_req_run(&req, enable_advertising_instance);
3840
3841 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003842 BT_ERR("Failed to re-configure advertising");
3843
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303844unlock:
3845 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003846}
3847
Marcel Holtmann21b51872013-10-10 09:47:53 -07003848static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3849 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003850{
3851 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003852 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003853 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003854 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003855 int err;
3856
3857 BT_DBG("request for %s", hdev->name);
3858
Johan Hedberge6fe7982013-10-02 15:45:22 +03003859 status = mgmt_le_support(hdev);
3860 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003861 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3862 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003863
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003864 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003865 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3866 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003867
3868 hci_dev_lock(hdev);
3869
3870 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003871
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003872 /* The following conditions are ones which mean that we should
3873 * not do any HCI communication but directly send a mgmt
3874 * response to user space (after toggling the flag if
3875 * necessary).
3876 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003877 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003878 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3879 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003880 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003881 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003882 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003883 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003884
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003885 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003886 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07003887 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003888 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003889 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003890 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003891 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003892 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003893 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003894 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003895 }
3896
3897 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3898 if (err < 0)
3899 goto unlock;
3900
3901 if (changed)
3902 err = new_settings(hdev, sk);
3903
3904 goto unlock;
3905 }
3906
Johan Hedberg333ae952015-03-17 13:48:47 +02003907 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3908 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003909 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3910 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03003911 goto unlock;
3912 }
3913
3914 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3915 if (!cmd) {
3916 err = -ENOMEM;
3917 goto unlock;
3918 }
3919
3920 hci_req_init(&req, hdev);
3921
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003922 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003923 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003924 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003925 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07003926
Florian Grandel7816b822015-06-18 03:16:45 +02003927 cancel_adv_timeout(hdev);
3928
Arman Uguray24b4f382015-03-23 15:57:12 -07003929 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02003930 /* Switch to instance "0" for the Set Advertising setting.
3931 * We cannot use update_[adv|scan_rsp]_data() here as the
3932 * HCI_ADVERTISING flag is not yet set.
3933 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02003934 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02003935 __hci_req_update_adv_data(&req, 0x00);
3936 __hci_req_update_scan_rsp_data(&req, 0x00);
3937 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003938 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02003939 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003940 }
Johan Hedberg4375f102013-09-25 13:26:10 +03003941
3942 err = hci_req_run(&req, set_advertising_complete);
3943 if (err < 0)
3944 mgmt_pending_remove(cmd);
3945
3946unlock:
3947 hci_dev_unlock(hdev);
3948 return err;
3949}
3950
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003951static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3952 void *data, u16 len)
3953{
3954 struct mgmt_cp_set_static_address *cp = data;
3955 int err;
3956
3957 BT_DBG("%s", hdev->name);
3958
Marcel Holtmann62af4442013-10-02 22:10:32 -07003959 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003960 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3961 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003962
3963 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003964 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3965 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003966
3967 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3968 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02003969 return mgmt_cmd_status(sk, hdev->id,
3970 MGMT_OP_SET_STATIC_ADDRESS,
3971 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003972
3973 /* Two most significant bits shall be set */
3974 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003975 return mgmt_cmd_status(sk, hdev->id,
3976 MGMT_OP_SET_STATIC_ADDRESS,
3977 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003978 }
3979
3980 hci_dev_lock(hdev);
3981
3982 bacpy(&hdev->static_addr, &cp->bdaddr);
3983
Marcel Holtmann93690c22015-03-06 10:11:21 -08003984 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
3985 if (err < 0)
3986 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003987
Marcel Holtmann93690c22015-03-06 10:11:21 -08003988 err = new_settings(hdev, sk);
3989
3990unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003991 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003992 return err;
3993}
3994
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003995static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3996 void *data, u16 len)
3997{
3998 struct mgmt_cp_set_scan_params *cp = data;
3999 __u16 interval, window;
4000 int err;
4001
4002 BT_DBG("%s", hdev->name);
4003
4004 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004005 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4006 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004007
4008 interval = __le16_to_cpu(cp->interval);
4009
4010 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004011 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4012 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004013
4014 window = __le16_to_cpu(cp->window);
4015
4016 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004017 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4018 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004019
Marcel Holtmann899e1072013-10-14 09:55:32 -07004020 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004021 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4022 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004023
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004024 hci_dev_lock(hdev);
4025
4026 hdev->le_scan_interval = interval;
4027 hdev->le_scan_window = window;
4028
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004029 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4030 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004031
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004032 /* If background scan is running, restart it so new parameters are
4033 * loaded.
4034 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004035 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004036 hdev->discovery.state == DISCOVERY_STOPPED) {
4037 struct hci_request req;
4038
4039 hci_req_init(&req, hdev);
4040
4041 hci_req_add_le_scan_disable(&req);
4042 hci_req_add_le_passive_scan(&req);
4043
4044 hci_req_run(&req, NULL);
4045 }
4046
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004047 hci_dev_unlock(hdev);
4048
4049 return err;
4050}
4051
Marcel Holtmann1904a852015-01-11 13:50:44 -08004052static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4053 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004054{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004055 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004056
4057 BT_DBG("status 0x%02x", status);
4058
4059 hci_dev_lock(hdev);
4060
Johan Hedberg333ae952015-03-17 13:48:47 +02004061 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004062 if (!cmd)
4063 goto unlock;
4064
4065 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004066 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4067 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004068 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004069 struct mgmt_mode *cp = cmd->param;
4070
4071 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004072 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004073 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004074 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004075
Johan Hedberg33e38b32013-03-15 17:07:05 -05004076 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4077 new_settings(hdev, cmd->sk);
4078 }
4079
4080 mgmt_pending_remove(cmd);
4081
4082unlock:
4083 hci_dev_unlock(hdev);
4084}
4085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004086static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004087 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004089 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004090 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004091 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004092 int err;
4093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004094 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004095
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004096 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004097 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004098 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4099 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004100
Johan Hedberga7e80f22013-01-09 16:05:19 +02004101 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004102 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4103 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004104
Antti Julkuf6422ec2011-06-22 13:11:56 +03004105 hci_dev_lock(hdev);
4106
Johan Hedberg333ae952015-03-17 13:48:47 +02004107 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004108 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4109 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004110 goto unlock;
4111 }
4112
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004113 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004114 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4115 hdev);
4116 goto unlock;
4117 }
4118
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004119 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004120 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004121 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4122 hdev);
4123 new_settings(hdev, sk);
4124 goto unlock;
4125 }
4126
Johan Hedberg33e38b32013-03-15 17:07:05 -05004127 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4128 data, len);
4129 if (!cmd) {
4130 err = -ENOMEM;
4131 goto unlock;
4132 }
4133
4134 hci_req_init(&req, hdev);
4135
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004136 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004137
4138 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004139 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004140 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4141 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004142 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004143 }
4144
Johan Hedberg33e38b32013-03-15 17:07:05 -05004145unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004146 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004147
Antti Julkuf6422ec2011-06-22 13:11:56 +03004148 return err;
4149}
4150
Marcel Holtmann1904a852015-01-11 13:50:44 -08004151static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004152{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004153 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004154
4155 BT_DBG("status 0x%02x", status);
4156
4157 hci_dev_lock(hdev);
4158
Johan Hedberg333ae952015-03-17 13:48:47 +02004159 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004160 if (!cmd)
4161 goto unlock;
4162
4163 if (status) {
4164 u8 mgmt_err = mgmt_status(status);
4165
4166 /* We need to restore the flag if related HCI commands
4167 * failed.
4168 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004169 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004170
Johan Hedberga69e8372015-03-06 21:08:53 +02004171 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004172 } else {
4173 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4174 new_settings(hdev, cmd->sk);
4175 }
4176
4177 mgmt_pending_remove(cmd);
4178
4179unlock:
4180 hci_dev_unlock(hdev);
4181}
4182
4183static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4184{
4185 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004186 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004187 struct hci_request req;
4188 int err;
4189
4190 BT_DBG("request for %s", hdev->name);
4191
4192 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004193 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4194 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004195
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004196 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004197 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4198 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004199
4200 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004201 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4202 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004203
4204 hci_dev_lock(hdev);
4205
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004206 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004207 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4208 goto unlock;
4209 }
4210
4211 if (!hdev_is_powered(hdev)) {
4212 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004213 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4214 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4215 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4216 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4217 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004218 }
4219
Marcel Holtmannce05d602015-03-13 02:11:03 -07004220 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004221
4222 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4223 if (err < 0)
4224 goto unlock;
4225
4226 err = new_settings(hdev, sk);
4227 goto unlock;
4228 }
4229
4230 /* Reject disabling when powered on */
4231 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004232 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4233 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004234 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004235 } else {
4236 /* When configuring a dual-mode controller to operate
4237 * with LE only and using a static address, then switching
4238 * BR/EDR back on is not allowed.
4239 *
4240 * Dual-mode controllers shall operate with the public
4241 * address as its identity address for BR/EDR and LE. So
4242 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004243 *
4244 * The same restrictions applies when secure connections
4245 * has been enabled. For BR/EDR this is a controller feature
4246 * while for LE it is a host stack feature. This means that
4247 * switching BR/EDR back on when secure connections has been
4248 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004249 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004250 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004251 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004252 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004253 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4254 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004255 goto unlock;
4256 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004257 }
4258
Johan Hedberg333ae952015-03-17 13:48:47 +02004259 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004260 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4261 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004262 goto unlock;
4263 }
4264
4265 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4266 if (!cmd) {
4267 err = -ENOMEM;
4268 goto unlock;
4269 }
4270
Johan Hedbergf2252572015-11-18 12:49:20 +02004271 /* We need to flip the bit already here so that
4272 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004273 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004274 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004275
4276 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004277
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004278 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004279 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004280
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004281 /* Since only the advertising data flags will change, there
4282 * is no need to update the scan response data.
4283 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004284 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004285
Johan Hedberg0663ca22013-10-02 13:43:14 +03004286 err = hci_req_run(&req, set_bredr_complete);
4287 if (err < 0)
4288 mgmt_pending_remove(cmd);
4289
4290unlock:
4291 hci_dev_unlock(hdev);
4292 return err;
4293}
4294
Johan Hedberga1443f52015-01-23 15:42:46 +02004295static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4296{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004297 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004298 struct mgmt_mode *cp;
4299
4300 BT_DBG("%s status %u", hdev->name, status);
4301
4302 hci_dev_lock(hdev);
4303
Johan Hedberg333ae952015-03-17 13:48:47 +02004304 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004305 if (!cmd)
4306 goto unlock;
4307
4308 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004309 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4310 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004311 goto remove;
4312 }
4313
4314 cp = cmd->param;
4315
4316 switch (cp->val) {
4317 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004318 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4319 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004320 break;
4321 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004322 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004323 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004324 break;
4325 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004326 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4327 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004328 break;
4329 }
4330
4331 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4332 new_settings(hdev, cmd->sk);
4333
4334remove:
4335 mgmt_pending_remove(cmd);
4336unlock:
4337 hci_dev_unlock(hdev);
4338}
4339
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004340static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4341 void *data, u16 len)
4342{
4343 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004344 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004345 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004346 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004347 int err;
4348
4349 BT_DBG("request for %s", hdev->name);
4350
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004351 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004352 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004353 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4354 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004355
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004356 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004357 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004358 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004359 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4360 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004361
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004362 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004363 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004364 MGMT_STATUS_INVALID_PARAMS);
4365
4366 hci_dev_lock(hdev);
4367
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004368 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004369 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004370 bool changed;
4371
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004372 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004373 changed = !hci_dev_test_and_set_flag(hdev,
4374 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004375 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004376 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004377 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004378 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004379 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004380 changed = hci_dev_test_and_clear_flag(hdev,
4381 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004382 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004383 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004384
4385 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4386 if (err < 0)
4387 goto failed;
4388
4389 if (changed)
4390 err = new_settings(hdev, sk);
4391
4392 goto failed;
4393 }
4394
Johan Hedberg333ae952015-03-17 13:48:47 +02004395 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004396 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4397 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004398 goto failed;
4399 }
4400
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004401 val = !!cp->val;
4402
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004403 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4404 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004405 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4406 goto failed;
4407 }
4408
4409 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4410 if (!cmd) {
4411 err = -ENOMEM;
4412 goto failed;
4413 }
4414
Johan Hedberga1443f52015-01-23 15:42:46 +02004415 hci_req_init(&req, hdev);
4416 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4417 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004418 if (err < 0) {
4419 mgmt_pending_remove(cmd);
4420 goto failed;
4421 }
4422
4423failed:
4424 hci_dev_unlock(hdev);
4425 return err;
4426}
4427
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004428static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4429 void *data, u16 len)
4430{
4431 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004432 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004433 int err;
4434
4435 BT_DBG("request for %s", hdev->name);
4436
Johan Hedbergb97109792014-06-24 14:00:28 +03004437 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004438 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4439 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004440
4441 hci_dev_lock(hdev);
4442
4443 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004444 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004445 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004446 changed = hci_dev_test_and_clear_flag(hdev,
4447 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004448
Johan Hedbergb97109792014-06-24 14:00:28 +03004449 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004450 use_changed = !hci_dev_test_and_set_flag(hdev,
4451 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004452 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004453 use_changed = hci_dev_test_and_clear_flag(hdev,
4454 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004455
4456 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004457 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004458 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4459 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4460 sizeof(mode), &mode);
4461 }
4462
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004463 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4464 if (err < 0)
4465 goto unlock;
4466
4467 if (changed)
4468 err = new_settings(hdev, sk);
4469
4470unlock:
4471 hci_dev_unlock(hdev);
4472 return err;
4473}
4474
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004475static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4476 u16 len)
4477{
4478 struct mgmt_cp_set_privacy *cp = cp_data;
4479 bool changed;
4480 int err;
4481
4482 BT_DBG("request for %s", hdev->name);
4483
4484 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004485 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4486 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004487
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004488 if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004489 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4490 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004491
4492 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004493 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4494 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004495
4496 hci_dev_lock(hdev);
4497
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004498 /* If user space supports this command it is also expected to
4499 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4500 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004501 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004502
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004503 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004504 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004505 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004506 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004507 if (cp->privacy == 0x02)
4508 hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
4509 else
4510 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004511 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004512 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004513 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004514 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg82a37ad2016-03-09 17:30:34 +02004515 hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004516 }
4517
4518 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4519 if (err < 0)
4520 goto unlock;
4521
4522 if (changed)
4523 err = new_settings(hdev, sk);
4524
4525unlock:
4526 hci_dev_unlock(hdev);
4527 return err;
4528}
4529
Johan Hedberg41edf162014-02-18 10:19:35 +02004530static bool irk_is_valid(struct mgmt_irk_info *irk)
4531{
4532 switch (irk->addr.type) {
4533 case BDADDR_LE_PUBLIC:
4534 return true;
4535
4536 case BDADDR_LE_RANDOM:
4537 /* Two most significant bits shall be set */
4538 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4539 return false;
4540 return true;
4541 }
4542
4543 return false;
4544}
4545
4546static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4547 u16 len)
4548{
4549 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004550 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4551 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004552 u16 irk_count, expected_len;
4553 int i, err;
4554
4555 BT_DBG("request for %s", hdev->name);
4556
4557 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004558 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4559 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004560
4561 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004562 if (irk_count > max_irk_count) {
4563 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004564 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4565 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004566 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004567
4568 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4569 if (expected_len != len) {
4570 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004571 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4573 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004574 }
4575
4576 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4577
4578 for (i = 0; i < irk_count; i++) {
4579 struct mgmt_irk_info *key = &cp->irks[i];
4580
4581 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004582 return mgmt_cmd_status(sk, hdev->id,
4583 MGMT_OP_LOAD_IRKS,
4584 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004585 }
4586
4587 hci_dev_lock(hdev);
4588
4589 hci_smp_irks_clear(hdev);
4590
4591 for (i = 0; i < irk_count; i++) {
4592 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004593
Johan Hedberg85813a72015-10-21 18:02:59 +03004594 hci_add_irk(hdev, &irk->addr.bdaddr,
4595 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004596 BDADDR_ANY);
4597 }
4598
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004599 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004600
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004601 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004602
4603 hci_dev_unlock(hdev);
4604
4605 return err;
4606}
4607
Johan Hedberg3f706b72013-01-20 14:27:16 +02004608static bool ltk_is_valid(struct mgmt_ltk_info *key)
4609{
4610 if (key->master != 0x00 && key->master != 0x01)
4611 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004612
4613 switch (key->addr.type) {
4614 case BDADDR_LE_PUBLIC:
4615 return true;
4616
4617 case BDADDR_LE_RANDOM:
4618 /* Two most significant bits shall be set */
4619 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4620 return false;
4621 return true;
4622 }
4623
4624 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004625}
4626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004627static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004628 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004629{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004630 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004631 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4632 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004633 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004634 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004635
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004636 BT_DBG("request for %s", hdev->name);
4637
4638 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004639 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4640 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004641
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004642 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004643 if (key_count > max_key_count) {
4644 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004645 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4646 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004647 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004648
4649 expected_len = sizeof(*cp) + key_count *
4650 sizeof(struct mgmt_ltk_info);
4651 if (expected_len != len) {
4652 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004653 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004654 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4655 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004656 }
4657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004658 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004659
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004660 for (i = 0; i < key_count; i++) {
4661 struct mgmt_ltk_info *key = &cp->keys[i];
4662
Johan Hedberg3f706b72013-01-20 14:27:16 +02004663 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004664 return mgmt_cmd_status(sk, hdev->id,
4665 MGMT_OP_LOAD_LONG_TERM_KEYS,
4666 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004667 }
4668
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004669 hci_dev_lock(hdev);
4670
4671 hci_smp_ltks_clear(hdev);
4672
4673 for (i = 0; i < key_count; i++) {
4674 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004675 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004676
Johan Hedberg61b43352014-05-29 19:36:53 +03004677 switch (key->type) {
4678 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004679 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004680 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004681 break;
4682 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004683 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004684 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004685 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004686 case MGMT_LTK_P256_UNAUTH:
4687 authenticated = 0x00;
4688 type = SMP_LTK_P256;
4689 break;
4690 case MGMT_LTK_P256_AUTH:
4691 authenticated = 0x01;
4692 type = SMP_LTK_P256;
4693 break;
4694 case MGMT_LTK_P256_DEBUG:
4695 authenticated = 0x00;
4696 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004697 default:
4698 continue;
4699 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004700
Johan Hedberg85813a72015-10-21 18:02:59 +03004701 hci_add_ltk(hdev, &key->addr.bdaddr,
4702 le_addr_type(key->addr.type), type, authenticated,
4703 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004704 }
4705
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004706 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004707 NULL, 0);
4708
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004709 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004710
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004711 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004712}
4713
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004714static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004715{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004716 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004717 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004718 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004719
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004720 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004721
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004722 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004723 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004724 rp.tx_power = conn->tx_power;
4725 rp.max_tx_power = conn->max_tx_power;
4726 } else {
4727 rp.rssi = HCI_RSSI_INVALID;
4728 rp.tx_power = HCI_TX_POWER_INVALID;
4729 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004730 }
4731
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004732 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4733 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004734
4735 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004736 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004737
4738 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004739}
4740
Marcel Holtmann1904a852015-01-11 13:50:44 -08004741static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4742 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004743{
4744 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004745 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004746 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004747 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004748 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004749
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004750 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004751
4752 hci_dev_lock(hdev);
4753
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004754 /* Commands sent in request are either Read RSSI or Read Transmit Power
4755 * Level so we check which one was last sent to retrieve connection
4756 * handle. Both commands have handle as first parameter so it's safe to
4757 * cast data on the same command struct.
4758 *
4759 * First command sent is always Read RSSI and we fail only if it fails.
4760 * In other case we simply override error to indicate success as we
4761 * already remembered if TX power value is actually valid.
4762 */
4763 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4764 if (!cp) {
4765 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004766 status = MGMT_STATUS_SUCCESS;
4767 } else {
4768 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004769 }
4770
4771 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004772 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004773 goto unlock;
4774 }
4775
4776 handle = __le16_to_cpu(cp->handle);
4777 conn = hci_conn_hash_lookup_handle(hdev, handle);
4778 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004779 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004780 goto unlock;
4781 }
4782
Johan Hedberg333ae952015-03-17 13:48:47 +02004783 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004784 if (!cmd)
4785 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004786
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004787 cmd->cmd_complete(cmd, status);
4788 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004789
4790unlock:
4791 hci_dev_unlock(hdev);
4792}
4793
4794static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4795 u16 len)
4796{
4797 struct mgmt_cp_get_conn_info *cp = data;
4798 struct mgmt_rp_get_conn_info rp;
4799 struct hci_conn *conn;
4800 unsigned long conn_info_age;
4801 int err = 0;
4802
4803 BT_DBG("%s", hdev->name);
4804
4805 memset(&rp, 0, sizeof(rp));
4806 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4807 rp.addr.type = cp->addr.type;
4808
4809 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004810 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4811 MGMT_STATUS_INVALID_PARAMS,
4812 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004813
4814 hci_dev_lock(hdev);
4815
4816 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004817 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4818 MGMT_STATUS_NOT_POWERED, &rp,
4819 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004820 goto unlock;
4821 }
4822
4823 if (cp->addr.type == BDADDR_BREDR)
4824 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4825 &cp->addr.bdaddr);
4826 else
4827 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4828
4829 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004830 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4831 MGMT_STATUS_NOT_CONNECTED, &rp,
4832 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004833 goto unlock;
4834 }
4835
Johan Hedberg333ae952015-03-17 13:48:47 +02004836 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004837 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4838 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004839 goto unlock;
4840 }
4841
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004842 /* To avoid client trying to guess when to poll again for information we
4843 * calculate conn info age as random value between min/max set in hdev.
4844 */
4845 conn_info_age = hdev->conn_info_min_age +
4846 prandom_u32_max(hdev->conn_info_max_age -
4847 hdev->conn_info_min_age);
4848
4849 /* Query controller to refresh cached values if they are too old or were
4850 * never read.
4851 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004852 if (time_after(jiffies, conn->conn_info_timestamp +
4853 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004854 !conn->conn_info_timestamp) {
4855 struct hci_request req;
4856 struct hci_cp_read_tx_power req_txp_cp;
4857 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004858 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004859
4860 hci_req_init(&req, hdev);
4861 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4862 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4863 &req_rssi_cp);
4864
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004865 /* For LE links TX power does not change thus we don't need to
4866 * query for it once value is known.
4867 */
4868 if (!bdaddr_type_is_le(cp->addr.type) ||
4869 conn->tx_power == HCI_TX_POWER_INVALID) {
4870 req_txp_cp.handle = cpu_to_le16(conn->handle);
4871 req_txp_cp.type = 0x00;
4872 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4873 sizeof(req_txp_cp), &req_txp_cp);
4874 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004875
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004876 /* Max TX power needs to be read only once per connection */
4877 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4878 req_txp_cp.handle = cpu_to_le16(conn->handle);
4879 req_txp_cp.type = 0x01;
4880 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4881 sizeof(req_txp_cp), &req_txp_cp);
4882 }
4883
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004884 err = hci_req_run(&req, conn_info_refresh_complete);
4885 if (err < 0)
4886 goto unlock;
4887
4888 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4889 data, len);
4890 if (!cmd) {
4891 err = -ENOMEM;
4892 goto unlock;
4893 }
4894
4895 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004896 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004897 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004898
4899 conn->conn_info_timestamp = jiffies;
4900 } else {
4901 /* Cache is valid, just reply with values cached in hci_conn */
4902 rp.rssi = conn->rssi;
4903 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004904 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004905
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004906 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4907 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004908 }
4909
4910unlock:
4911 hci_dev_unlock(hdev);
4912 return err;
4913}
4914
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004915static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004916{
4917 struct hci_conn *conn = cmd->user_data;
4918 struct mgmt_rp_get_clock_info rp;
4919 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004920 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004921
4922 memset(&rp, 0, sizeof(rp));
Marcel Holtmann56f787c2016-08-29 06:19:47 +02004923 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Johan Hedberg69487372014-12-05 13:36:07 +02004924
4925 if (status)
4926 goto complete;
4927
4928 hdev = hci_dev_get(cmd->index);
4929 if (hdev) {
4930 rp.local_clock = cpu_to_le32(hdev->clock);
4931 hci_dev_put(hdev);
4932 }
4933
4934 if (conn) {
4935 rp.piconet_clock = cpu_to_le32(conn->clock);
4936 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
4937 }
4938
4939complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004940 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
4941 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02004942
4943 if (conn) {
4944 hci_conn_drop(conn);
4945 hci_conn_put(conn);
4946 }
Johan Hedberg9df74652014-12-19 22:26:03 +02004947
4948 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02004949}
4950
Marcel Holtmann1904a852015-01-11 13:50:44 -08004951static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03004952{
Johan Hedberg95868422014-06-28 17:54:07 +03004953 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004954 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004955 struct hci_conn *conn;
4956
4957 BT_DBG("%s status %u", hdev->name, status);
4958
4959 hci_dev_lock(hdev);
4960
4961 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
4962 if (!hci_cp)
4963 goto unlock;
4964
4965 if (hci_cp->which) {
4966 u16 handle = __le16_to_cpu(hci_cp->handle);
4967 conn = hci_conn_hash_lookup_handle(hdev, handle);
4968 } else {
4969 conn = NULL;
4970 }
4971
Johan Hedberg333ae952015-03-17 13:48:47 +02004972 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004973 if (!cmd)
4974 goto unlock;
4975
Johan Hedberg69487372014-12-05 13:36:07 +02004976 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03004977 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03004978
4979unlock:
4980 hci_dev_unlock(hdev);
4981}
4982
4983static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
4984 u16 len)
4985{
4986 struct mgmt_cp_get_clock_info *cp = data;
4987 struct mgmt_rp_get_clock_info rp;
4988 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004989 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004990 struct hci_request req;
4991 struct hci_conn *conn;
4992 int err;
4993
4994 BT_DBG("%s", hdev->name);
4995
4996 memset(&rp, 0, sizeof(rp));
4997 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4998 rp.addr.type = cp->addr.type;
4999
5000 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005001 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5002 MGMT_STATUS_INVALID_PARAMS,
5003 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005004
5005 hci_dev_lock(hdev);
5006
5007 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005008 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5009 MGMT_STATUS_NOT_POWERED, &rp,
5010 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005011 goto unlock;
5012 }
5013
5014 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5015 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5016 &cp->addr.bdaddr);
5017 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005018 err = mgmt_cmd_complete(sk, hdev->id,
5019 MGMT_OP_GET_CLOCK_INFO,
5020 MGMT_STATUS_NOT_CONNECTED,
5021 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005022 goto unlock;
5023 }
5024 } else {
5025 conn = NULL;
5026 }
5027
5028 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5029 if (!cmd) {
5030 err = -ENOMEM;
5031 goto unlock;
5032 }
5033
Johan Hedberg69487372014-12-05 13:36:07 +02005034 cmd->cmd_complete = clock_info_cmd_complete;
5035
Johan Hedberg95868422014-06-28 17:54:07 +03005036 hci_req_init(&req, hdev);
5037
5038 memset(&hci_cp, 0, sizeof(hci_cp));
5039 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5040
5041 if (conn) {
5042 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005043 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005044
5045 hci_cp.handle = cpu_to_le16(conn->handle);
5046 hci_cp.which = 0x01; /* Piconet clock */
5047 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5048 }
5049
5050 err = hci_req_run(&req, get_clock_info_complete);
5051 if (err < 0)
5052 mgmt_pending_remove(cmd);
5053
5054unlock:
5055 hci_dev_unlock(hdev);
5056 return err;
5057}
5058
Johan Hedberg5a154e62014-12-19 22:26:02 +02005059static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5060{
5061 struct hci_conn *conn;
5062
5063 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5064 if (!conn)
5065 return false;
5066
5067 if (conn->dst_type != type)
5068 return false;
5069
5070 if (conn->state != BT_CONNECTED)
5071 return false;
5072
5073 return true;
5074}
5075
5076/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005077static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005078 u8 addr_type, u8 auto_connect)
5079{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005080 struct hci_conn_params *params;
5081
5082 params = hci_conn_params_add(hdev, addr, addr_type);
5083 if (!params)
5084 return -EIO;
5085
5086 if (params->auto_connect == auto_connect)
5087 return 0;
5088
5089 list_del_init(&params->action);
5090
5091 switch (auto_connect) {
5092 case HCI_AUTO_CONN_DISABLED:
5093 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005094 /* If auto connect is being disabled when we're trying to
5095 * connect to device, keep connecting.
5096 */
5097 if (params->explicit_connect)
5098 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005099 break;
5100 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005101 if (params->explicit_connect)
5102 list_add(&params->action, &hdev->pend_le_conns);
5103 else
5104 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005105 break;
5106 case HCI_AUTO_CONN_DIRECT:
5107 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005108 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005109 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005110 break;
5111 }
5112
5113 params->auto_connect = auto_connect;
5114
5115 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5116 auto_connect);
5117
5118 return 0;
5119}
5120
Marcel Holtmann8afef092014-06-29 22:28:34 +02005121static void device_added(struct sock *sk, struct hci_dev *hdev,
5122 bdaddr_t *bdaddr, u8 type, u8 action)
5123{
5124 struct mgmt_ev_device_added ev;
5125
5126 bacpy(&ev.addr.bdaddr, bdaddr);
5127 ev.addr.type = type;
5128 ev.action = action;
5129
5130 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5131}
5132
Marcel Holtmann2faade52014-06-29 19:44:03 +02005133static int add_device(struct sock *sk, struct hci_dev *hdev,
5134 void *data, u16 len)
5135{
5136 struct mgmt_cp_add_device *cp = data;
5137 u8 auto_conn, addr_type;
5138 int err;
5139
5140 BT_DBG("%s", hdev->name);
5141
Johan Hedberg66593582014-07-09 12:59:14 +03005142 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005143 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005144 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5145 MGMT_STATUS_INVALID_PARAMS,
5146 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005147
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005148 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005149 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5150 MGMT_STATUS_INVALID_PARAMS,
5151 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005152
5153 hci_dev_lock(hdev);
5154
Johan Hedberg66593582014-07-09 12:59:14 +03005155 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005156 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005157 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005158 err = mgmt_cmd_complete(sk, hdev->id,
5159 MGMT_OP_ADD_DEVICE,
5160 MGMT_STATUS_INVALID_PARAMS,
5161 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005162 goto unlock;
5163 }
5164
5165 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5166 cp->addr.type);
5167 if (err)
5168 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005169
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005170 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005171
Johan Hedberg66593582014-07-09 12:59:14 +03005172 goto added;
5173 }
5174
Johan Hedberg85813a72015-10-21 18:02:59 +03005175 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005176
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005177 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005178 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005179 else if (cp->action == 0x01)
5180 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005181 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005182 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005183
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005184 /* Kernel internally uses conn_params with resolvable private
5185 * address, but Add Device allows only identity addresses.
5186 * Make sure it is enforced before calling
5187 * hci_conn_params_lookup.
5188 */
5189 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005190 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5191 MGMT_STATUS_INVALID_PARAMS,
5192 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005193 goto unlock;
5194 }
5195
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005196 /* If the connection parameters don't exist for this device,
5197 * they will be created and configured with defaults.
5198 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005199 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005200 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005201 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5202 MGMT_STATUS_FAILED, &cp->addr,
5203 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005204 goto unlock;
5205 }
5206
Johan Hedberg51d7a942015-11-11 08:11:18 +02005207 hci_update_background_scan(hdev);
5208
Johan Hedberg66593582014-07-09 12:59:14 +03005209added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005210 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5211
Johan Hedberg51d7a942015-11-11 08:11:18 +02005212 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5213 MGMT_STATUS_SUCCESS, &cp->addr,
5214 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005215
5216unlock:
5217 hci_dev_unlock(hdev);
5218 return err;
5219}
5220
Marcel Holtmann8afef092014-06-29 22:28:34 +02005221static void device_removed(struct sock *sk, struct hci_dev *hdev,
5222 bdaddr_t *bdaddr, u8 type)
5223{
5224 struct mgmt_ev_device_removed ev;
5225
5226 bacpy(&ev.addr.bdaddr, bdaddr);
5227 ev.addr.type = type;
5228
5229 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5230}
5231
Marcel Holtmann2faade52014-06-29 19:44:03 +02005232static int remove_device(struct sock *sk, struct hci_dev *hdev,
5233 void *data, u16 len)
5234{
5235 struct mgmt_cp_remove_device *cp = data;
5236 int err;
5237
5238 BT_DBG("%s", hdev->name);
5239
5240 hci_dev_lock(hdev);
5241
5242 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005243 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005244 u8 addr_type;
5245
Johan Hedberg66593582014-07-09 12:59:14 +03005246 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005247 err = mgmt_cmd_complete(sk, hdev->id,
5248 MGMT_OP_REMOVE_DEVICE,
5249 MGMT_STATUS_INVALID_PARAMS,
5250 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005251 goto unlock;
5252 }
5253
Johan Hedberg66593582014-07-09 12:59:14 +03005254 if (cp->addr.type == BDADDR_BREDR) {
5255 err = hci_bdaddr_list_del(&hdev->whitelist,
5256 &cp->addr.bdaddr,
5257 cp->addr.type);
5258 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005259 err = mgmt_cmd_complete(sk, hdev->id,
5260 MGMT_OP_REMOVE_DEVICE,
5261 MGMT_STATUS_INVALID_PARAMS,
5262 &cp->addr,
5263 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005264 goto unlock;
5265 }
5266
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005267 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005268
Johan Hedberg66593582014-07-09 12:59:14 +03005269 device_removed(sk, hdev, &cp->addr.bdaddr,
5270 cp->addr.type);
5271 goto complete;
5272 }
5273
Johan Hedberg85813a72015-10-21 18:02:59 +03005274 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005275
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005276 /* Kernel internally uses conn_params with resolvable private
5277 * address, but Remove Device allows only identity addresses.
5278 * Make sure it is enforced before calling
5279 * hci_conn_params_lookup.
5280 */
5281 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005282 err = mgmt_cmd_complete(sk, hdev->id,
5283 MGMT_OP_REMOVE_DEVICE,
5284 MGMT_STATUS_INVALID_PARAMS,
5285 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005286 goto unlock;
5287 }
5288
Johan Hedbergc71593d2014-07-02 17:37:28 +03005289 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5290 addr_type);
5291 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005292 err = mgmt_cmd_complete(sk, hdev->id,
5293 MGMT_OP_REMOVE_DEVICE,
5294 MGMT_STATUS_INVALID_PARAMS,
5295 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005296 goto unlock;
5297 }
5298
Johan Hedberg679d2b62015-10-16 10:07:52 +03005299 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5300 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005301 err = mgmt_cmd_complete(sk, hdev->id,
5302 MGMT_OP_REMOVE_DEVICE,
5303 MGMT_STATUS_INVALID_PARAMS,
5304 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005305 goto unlock;
5306 }
5307
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005308 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005309 list_del(&params->list);
5310 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005311 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005312
5313 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005314 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005315 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005316 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005317
Marcel Holtmann2faade52014-06-29 19:44:03 +02005318 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005319 err = mgmt_cmd_complete(sk, hdev->id,
5320 MGMT_OP_REMOVE_DEVICE,
5321 MGMT_STATUS_INVALID_PARAMS,
5322 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005323 goto unlock;
5324 }
5325
Johan Hedberg66593582014-07-09 12:59:14 +03005326 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5327 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5328 list_del(&b->list);
5329 kfree(b);
5330 }
5331
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005332 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005333
Johan Hedberg19de0822014-07-06 13:06:51 +03005334 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5335 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5336 continue;
5337 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005338 if (p->explicit_connect) {
5339 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5340 continue;
5341 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005342 list_del(&p->action);
5343 list_del(&p->list);
5344 kfree(p);
5345 }
5346
5347 BT_DBG("All LE connection parameters were removed");
5348
Johan Hedberg51d7a942015-11-11 08:11:18 +02005349 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005350 }
5351
Johan Hedberg66593582014-07-09 12:59:14 +03005352complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005353 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5354 MGMT_STATUS_SUCCESS, &cp->addr,
5355 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005356unlock:
5357 hci_dev_unlock(hdev);
5358 return err;
5359}
5360
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005361static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5362 u16 len)
5363{
5364 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005365 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5366 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005367 u16 param_count, expected_len;
5368 int i;
5369
5370 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005371 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5372 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005373
5374 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005375 if (param_count > max_param_count) {
5376 BT_ERR("load_conn_param: too big param_count value %u",
5377 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005378 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5379 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005380 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005381
5382 expected_len = sizeof(*cp) + param_count *
5383 sizeof(struct mgmt_conn_param);
5384 if (expected_len != len) {
5385 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5386 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005387 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5388 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005389 }
5390
5391 BT_DBG("%s param_count %u", hdev->name, param_count);
5392
5393 hci_dev_lock(hdev);
5394
5395 hci_conn_params_clear_disabled(hdev);
5396
5397 for (i = 0; i < param_count; i++) {
5398 struct mgmt_conn_param *param = &cp->params[i];
5399 struct hci_conn_params *hci_param;
5400 u16 min, max, latency, timeout;
5401 u8 addr_type;
5402
5403 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5404 param->addr.type);
5405
5406 if (param->addr.type == BDADDR_LE_PUBLIC) {
5407 addr_type = ADDR_LE_DEV_PUBLIC;
5408 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5409 addr_type = ADDR_LE_DEV_RANDOM;
5410 } else {
5411 BT_ERR("Ignoring invalid connection parameters");
5412 continue;
5413 }
5414
5415 min = le16_to_cpu(param->min_interval);
5416 max = le16_to_cpu(param->max_interval);
5417 latency = le16_to_cpu(param->latency);
5418 timeout = le16_to_cpu(param->timeout);
5419
5420 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5421 min, max, latency, timeout);
5422
5423 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5424 BT_ERR("Ignoring invalid connection parameters");
5425 continue;
5426 }
5427
5428 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5429 addr_type);
5430 if (!hci_param) {
5431 BT_ERR("Failed to add connection parameters");
5432 continue;
5433 }
5434
5435 hci_param->conn_min_interval = min;
5436 hci_param->conn_max_interval = max;
5437 hci_param->conn_latency = latency;
5438 hci_param->supervision_timeout = timeout;
5439 }
5440
5441 hci_dev_unlock(hdev);
5442
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005443 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5444 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005445}
5446
Marcel Holtmanndbece372014-07-04 18:11:55 +02005447static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5448 void *data, u16 len)
5449{
5450 struct mgmt_cp_set_external_config *cp = data;
5451 bool changed;
5452 int err;
5453
5454 BT_DBG("%s", hdev->name);
5455
5456 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005457 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5458 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005459
5460 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005461 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5462 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005463
5464 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005465 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5466 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005467
5468 hci_dev_lock(hdev);
5469
5470 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005471 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005472 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005473 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005474
5475 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5476 if (err < 0)
5477 goto unlock;
5478
5479 if (!changed)
5480 goto unlock;
5481
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005482 err = new_options(hdev, sk);
5483
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005484 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005485 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005486
Marcel Holtmann516018a2015-03-13 02:11:04 -07005487 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005488 hci_dev_set_flag(hdev, HCI_CONFIG);
5489 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005490
5491 queue_work(hdev->req_workqueue, &hdev->power_on);
5492 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005493 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02005494 mgmt_index_added(hdev);
5495 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005496 }
5497
5498unlock:
5499 hci_dev_unlock(hdev);
5500 return err;
5501}
5502
Marcel Holtmann9713c172014-07-06 12:11:15 +02005503static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5504 void *data, u16 len)
5505{
5506 struct mgmt_cp_set_public_address *cp = data;
5507 bool changed;
5508 int err;
5509
5510 BT_DBG("%s", hdev->name);
5511
5512 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005513 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5514 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005515
5516 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005517 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5518 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005519
5520 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005521 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5522 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005523
5524 hci_dev_lock(hdev);
5525
5526 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5527 bacpy(&hdev->public_addr, &cp->bdaddr);
5528
5529 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5530 if (err < 0)
5531 goto unlock;
5532
5533 if (!changed)
5534 goto unlock;
5535
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005536 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005537 err = new_options(hdev, sk);
5538
5539 if (is_configured(hdev)) {
5540 mgmt_index_removed(hdev);
5541
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005542 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005543
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005544 hci_dev_set_flag(hdev, HCI_CONFIG);
5545 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005546
5547 queue_work(hdev->req_workqueue, &hdev->power_on);
5548 }
5549
5550unlock:
5551 hci_dev_unlock(hdev);
5552 return err;
5553}
5554
Marcel Holtmannbea41602015-03-14 22:43:17 -07005555static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5556 u8 data_len)
5557{
5558 eir[eir_len++] = sizeof(type) + data_len;
5559 eir[eir_len++] = type;
5560 memcpy(&eir[eir_len], data, data_len);
5561 eir_len += data_len;
5562
5563 return eir_len;
5564}
5565
Johan Hedberg40f66c02015-04-07 21:52:22 +03005566static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5567 u16 opcode, struct sk_buff *skb)
5568{
5569 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5570 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5571 u8 *h192, *r192, *h256, *r256;
5572 struct mgmt_pending_cmd *cmd;
5573 u16 eir_len;
5574 int err;
5575
5576 BT_DBG("%s status %u", hdev->name, status);
5577
5578 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5579 if (!cmd)
5580 return;
5581
5582 mgmt_cp = cmd->param;
5583
5584 if (status) {
5585 status = mgmt_status(status);
5586 eir_len = 0;
5587
5588 h192 = NULL;
5589 r192 = NULL;
5590 h256 = NULL;
5591 r256 = NULL;
5592 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5593 struct hci_rp_read_local_oob_data *rp;
5594
5595 if (skb->len != sizeof(*rp)) {
5596 status = MGMT_STATUS_FAILED;
5597 eir_len = 0;
5598 } else {
5599 status = MGMT_STATUS_SUCCESS;
5600 rp = (void *)skb->data;
5601
5602 eir_len = 5 + 18 + 18;
5603 h192 = rp->hash;
5604 r192 = rp->rand;
5605 h256 = NULL;
5606 r256 = NULL;
5607 }
5608 } else {
5609 struct hci_rp_read_local_oob_ext_data *rp;
5610
5611 if (skb->len != sizeof(*rp)) {
5612 status = MGMT_STATUS_FAILED;
5613 eir_len = 0;
5614 } else {
5615 status = MGMT_STATUS_SUCCESS;
5616 rp = (void *)skb->data;
5617
5618 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5619 eir_len = 5 + 18 + 18;
5620 h192 = NULL;
5621 r192 = NULL;
5622 } else {
5623 eir_len = 5 + 18 + 18 + 18 + 18;
5624 h192 = rp->hash192;
5625 r192 = rp->rand192;
5626 }
5627
5628 h256 = rp->hash256;
5629 r256 = rp->rand256;
5630 }
5631 }
5632
5633 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5634 if (!mgmt_rp)
5635 goto done;
5636
5637 if (status)
5638 goto send_rsp;
5639
5640 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5641 hdev->dev_class, 3);
5642
5643 if (h192 && r192) {
5644 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5645 EIR_SSP_HASH_C192, h192, 16);
5646 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5647 EIR_SSP_RAND_R192, r192, 16);
5648 }
5649
5650 if (h256 && r256) {
5651 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5652 EIR_SSP_HASH_C256, h256, 16);
5653 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5654 EIR_SSP_RAND_R256, r256, 16);
5655 }
5656
5657send_rsp:
5658 mgmt_rp->type = mgmt_cp->type;
5659 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5660
5661 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5662 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5663 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5664 if (err < 0 || status)
5665 goto done;
5666
5667 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5668
5669 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5670 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5671 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5672done:
5673 kfree(mgmt_rp);
5674 mgmt_pending_remove(cmd);
5675}
5676
5677static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5678 struct mgmt_cp_read_local_oob_ext_data *cp)
5679{
5680 struct mgmt_pending_cmd *cmd;
5681 struct hci_request req;
5682 int err;
5683
5684 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5685 cp, sizeof(*cp));
5686 if (!cmd)
5687 return -ENOMEM;
5688
5689 hci_req_init(&req, hdev);
5690
5691 if (bredr_sc_enabled(hdev))
5692 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5693 else
5694 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5695
5696 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5697 if (err < 0) {
5698 mgmt_pending_remove(cmd);
5699 return err;
5700 }
5701
5702 return 0;
5703}
5704
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005705static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5706 void *data, u16 data_len)
5707{
5708 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5709 struct mgmt_rp_read_local_oob_ext_data *rp;
5710 size_t rp_len;
5711 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005712 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005713 int err;
5714
5715 BT_DBG("%s", hdev->name);
5716
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005717 if (hdev_is_powered(hdev)) {
5718 switch (cp->type) {
5719 case BIT(BDADDR_BREDR):
5720 status = mgmt_bredr_support(hdev);
5721 if (status)
5722 eir_len = 0;
5723 else
5724 eir_len = 5;
5725 break;
5726 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5727 status = mgmt_le_support(hdev);
5728 if (status)
5729 eir_len = 0;
5730 else
5731 eir_len = 9 + 3 + 18 + 18 + 3;
5732 break;
5733 default:
5734 status = MGMT_STATUS_INVALID_PARAMS;
5735 eir_len = 0;
5736 break;
5737 }
5738 } else {
5739 status = MGMT_STATUS_NOT_POWERED;
5740 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005741 }
5742
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005743 rp_len = sizeof(*rp) + eir_len;
5744 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005745 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005746 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005747
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005748 if (status)
5749 goto complete;
5750
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005751 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005752
5753 eir_len = 0;
5754 switch (cp->type) {
5755 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005756 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5757 err = read_local_ssp_oob_req(hdev, sk, cp);
5758 hci_dev_unlock(hdev);
5759 if (!err)
5760 goto done;
5761
5762 status = MGMT_STATUS_FAILED;
5763 goto complete;
5764 } else {
5765 eir_len = eir_append_data(rp->eir, eir_len,
5766 EIR_CLASS_OF_DEV,
5767 hdev->dev_class, 3);
5768 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005769 break;
5770 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005771 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5772 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005773 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005774 status = MGMT_STATUS_FAILED;
5775 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005776 }
5777
Marcel Holtmanne2135682015-04-02 12:00:58 -07005778 /* This should return the active RPA, but since the RPA
5779 * is only programmed on demand, it is really hard to fill
5780 * this in at the moment. For now disallow retrieving
5781 * local out-of-band data when privacy is in use.
5782 *
5783 * Returning the identity address will not help here since
5784 * pairing happens before the identity resolving key is
5785 * known and thus the connection establishment happens
5786 * based on the RPA and not the identity address.
5787 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005788 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005789 hci_dev_unlock(hdev);
5790 status = MGMT_STATUS_REJECTED;
5791 goto complete;
5792 }
5793
5794 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5795 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5796 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5797 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005798 memcpy(addr, &hdev->static_addr, 6);
5799 addr[6] = 0x01;
5800 } else {
5801 memcpy(addr, &hdev->bdaddr, 6);
5802 addr[6] = 0x00;
5803 }
5804
5805 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5806 addr, sizeof(addr));
5807
5808 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5809 role = 0x02;
5810 else
5811 role = 0x01;
5812
5813 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5814 &role, sizeof(role));
5815
Marcel Holtmann5082a592015-03-16 12:39:00 -07005816 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5817 eir_len = eir_append_data(rp->eir, eir_len,
5818 EIR_LE_SC_CONFIRM,
5819 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005820
Marcel Holtmann5082a592015-03-16 12:39:00 -07005821 eir_len = eir_append_data(rp->eir, eir_len,
5822 EIR_LE_SC_RANDOM,
5823 rand, sizeof(rand));
5824 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005825
Johan Hedbergf2252572015-11-18 12:49:20 +02005826 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005827
5828 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5829 flags |= LE_AD_NO_BREDR;
5830
5831 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5832 &flags, sizeof(flags));
5833 break;
5834 }
5835
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005836 hci_dev_unlock(hdev);
5837
Marcel Holtmann72000df2015-03-16 16:11:21 -07005838 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5839
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005840 status = MGMT_STATUS_SUCCESS;
5841
5842complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005843 rp->type = cp->type;
5844 rp->eir_len = cpu_to_le16(eir_len);
5845
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005846 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005847 status, rp, sizeof(*rp) + eir_len);
5848 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005849 goto done;
5850
5851 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5852 rp, sizeof(*rp) + eir_len,
5853 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005854
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005855done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005856 kfree(rp);
5857
5858 return err;
5859}
5860
Arman Uguray089fa8c2015-03-25 18:53:45 -07005861static u32 get_supported_adv_flags(struct hci_dev *hdev)
5862{
5863 u32 flags = 0;
5864
5865 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5866 flags |= MGMT_ADV_FLAG_DISCOV;
5867 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5868 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
5869
5870 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5871 flags |= MGMT_ADV_FLAG_TX_POWER;
5872
5873 return flags;
5874}
5875
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005876static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5877 void *data, u16 data_len)
5878{
5879 struct mgmt_rp_read_adv_features *rp;
5880 size_t rp_len;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005881 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005882 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005883 u32 supported_flags;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005884 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005885
5886 BT_DBG("%s", hdev->name);
5887
Arman Uguray089fa8c2015-03-25 18:53:45 -07005888 if (!lmp_le_capable(hdev))
5889 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5890 MGMT_STATUS_REJECTED);
5891
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005892 hci_dev_lock(hdev);
5893
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005894 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005895 rp = kmalloc(rp_len, GFP_ATOMIC);
5896 if (!rp) {
5897 hci_dev_unlock(hdev);
5898 return -ENOMEM;
5899 }
5900
Arman Uguray089fa8c2015-03-25 18:53:45 -07005901 supported_flags = get_supported_adv_flags(hdev);
5902
5903 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005904 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5905 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005906 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005907 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005908
Johan Hedberg02c04afe2015-11-26 12:15:58 +02005909 instance = rp->instance;
5910 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5911 *instance = adv_instance->instance;
5912 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005913 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005914
5915 hci_dev_unlock(hdev);
5916
5917 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5918 MGMT_STATUS_SUCCESS, rp, rp_len);
5919
5920 kfree(rp);
5921
5922 return err;
5923}
5924
Arman Uguray4117ed72015-03-23 15:57:14 -07005925static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005926 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005927{
Arman Uguray4117ed72015-03-23 15:57:14 -07005928 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005929 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005930 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005931 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005932
Marcel Holtmann31a32482015-11-19 16:16:42 +01005933 if (is_adv_data) {
5934 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5935 MGMT_ADV_FLAG_LIMITED_DISCOV |
5936 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5937 flags_managed = true;
5938 max_len -= 3;
5939 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005940
Marcel Holtmann31a32482015-11-19 16:16:42 +01005941 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5942 tx_power_managed = true;
5943 max_len -= 3;
5944 }
Arman Uguray5507e352015-03-25 18:53:44 -07005945 }
5946
Arman Uguray4117ed72015-03-23 15:57:14 -07005947 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005948 return false;
5949
Arman Uguray4117ed72015-03-23 15:57:14 -07005950 /* Make sure that the data is correctly formatted. */
5951 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
5952 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07005953
Arman Ugurayb44133f2015-03-25 18:53:41 -07005954 if (flags_managed && data[i + 1] == EIR_FLAGS)
5955 return false;
5956
Arman Uguray5507e352015-03-25 18:53:44 -07005957 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
5958 return false;
5959
Arman Uguray24b4f382015-03-23 15:57:12 -07005960 /* If the current field length would exceed the total data
5961 * length, then it's invalid.
5962 */
Arman Uguray4117ed72015-03-23 15:57:14 -07005963 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005964 return false;
5965 }
5966
5967 return true;
5968}
5969
Arman Uguray24b4f382015-03-23 15:57:12 -07005970static void add_advertising_complete(struct hci_dev *hdev, u8 status,
5971 u16 opcode)
5972{
5973 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005974 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07005975 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005976 struct adv_info *adv_instance, *n;
5977 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005978
5979 BT_DBG("status %d", status);
5980
5981 hci_dev_lock(hdev);
5982
5983 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
5984
Florian Grandelfffd38b2015-06-18 03:16:47 +02005985 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
5986 if (!adv_instance->pending)
5987 continue;
5988
5989 if (!status) {
5990 adv_instance->pending = false;
5991 continue;
5992 }
5993
5994 instance = adv_instance->instance;
5995
5996 if (hdev->cur_adv_instance == instance)
5997 cancel_adv_timeout(hdev);
5998
5999 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02006000 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006001 }
6002
6003 if (!cmd)
6004 goto unlock;
6005
Florian Grandelfffd38b2015-06-18 03:16:47 +02006006 cp = cmd->param;
6007 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006008
6009 if (status)
6010 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6011 mgmt_status(status));
6012 else
6013 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6014 mgmt_status(status), &rp, sizeof(rp));
6015
6016 mgmt_pending_remove(cmd);
6017
6018unlock:
6019 hci_dev_unlock(hdev);
6020}
6021
6022static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6023 void *data, u16 data_len)
6024{
6025 struct mgmt_cp_add_advertising *cp = data;
6026 struct mgmt_rp_add_advertising rp;
6027 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07006028 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07006029 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02006030 u16 timeout, duration;
6031 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
6032 u8 schedule_instance = 0;
6033 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006034 int err;
6035 struct mgmt_pending_cmd *cmd;
6036 struct hci_request req;
6037
6038 BT_DBG("%s", hdev->name);
6039
6040 status = mgmt_le_support(hdev);
6041 if (status)
6042 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6043 status);
6044
Marcel Holtmannceff86a2015-11-19 16:16:41 +01006045 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6046 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6047 MGMT_STATUS_INVALID_PARAMS);
6048
Johan Hedberg6a0e7802016-03-11 09:56:33 +02006049 if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
6050 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6051 MGMT_STATUS_INVALID_PARAMS);
6052
Arman Uguray24b4f382015-03-23 15:57:12 -07006053 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07006054 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006055 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07006056
Florian Grandelfffd38b2015-06-18 03:16:47 +02006057 /* The current implementation only supports a subset of the specified
6058 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07006059 */
6060 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02006061 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07006062 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6063 MGMT_STATUS_INVALID_PARAMS);
6064
6065 hci_dev_lock(hdev);
6066
Arman Uguray912098a2015-03-23 15:57:15 -07006067 if (timeout && !hdev_is_powered(hdev)) {
6068 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6069 MGMT_STATUS_REJECTED);
6070 goto unlock;
6071 }
6072
Arman Uguray24b4f382015-03-23 15:57:12 -07006073 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006074 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006075 pending_find(MGMT_OP_SET_LE, hdev)) {
6076 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6077 MGMT_STATUS_BUSY);
6078 goto unlock;
6079 }
6080
Arman Ugurayb44133f2015-03-25 18:53:41 -07006081 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006082 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006083 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006084 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6085 MGMT_STATUS_INVALID_PARAMS);
6086 goto unlock;
6087 }
6088
Florian Grandelfffd38b2015-06-18 03:16:47 +02006089 err = hci_add_adv_instance(hdev, cp->instance, flags,
6090 cp->adv_data_len, cp->data,
6091 cp->scan_rsp_len,
6092 cp->data + cp->adv_data_len,
6093 timeout, duration);
6094 if (err < 0) {
6095 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6096 MGMT_STATUS_FAILED);
6097 goto unlock;
6098 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006099
Florian Grandelfffd38b2015-06-18 03:16:47 +02006100 /* Only trigger an advertising added event if a new instance was
6101 * actually added.
6102 */
6103 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006104 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006105
Florian Grandelfffd38b2015-06-18 03:16:47 +02006106 if (hdev->cur_adv_instance == cp->instance) {
6107 /* If the currently advertised instance is being changed then
6108 * cancel the current advertising and schedule the next
6109 * instance. If there is only one instance then the overridden
6110 * advertising data will be visible right away.
6111 */
6112 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006113
Florian Grandelfffd38b2015-06-18 03:16:47 +02006114 next_instance = hci_get_next_instance(hdev, cp->instance);
6115 if (next_instance)
6116 schedule_instance = next_instance->instance;
6117 } else if (!hdev->adv_instance_timeout) {
6118 /* Immediately advertise the new instance if no other
6119 * instance is currently being advertised.
6120 */
6121 schedule_instance = cp->instance;
6122 }
Arman Uguray912098a2015-03-23 15:57:15 -07006123
Florian Grandelfffd38b2015-06-18 03:16:47 +02006124 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6125 * there is no instance to be advertised then we have no HCI
6126 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006127 */
6128 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006129 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6130 !schedule_instance) {
6131 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006132 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6133 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6134 goto unlock;
6135 }
6136
6137 /* We're good to go, update advertising data, parameters, and start
6138 * advertising.
6139 */
6140 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6141 data_len);
6142 if (!cmd) {
6143 err = -ENOMEM;
6144 goto unlock;
6145 }
6146
6147 hci_req_init(&req, hdev);
6148
Johan Hedbergf2252572015-11-18 12:49:20 +02006149 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006150
Florian Grandelfffd38b2015-06-18 03:16:47 +02006151 if (!err)
6152 err = hci_req_run(&req, add_advertising_complete);
6153
Arman Uguray24b4f382015-03-23 15:57:12 -07006154 if (err < 0)
6155 mgmt_pending_remove(cmd);
6156
6157unlock:
6158 hci_dev_unlock(hdev);
6159
6160 return err;
6161}
6162
Arman Ugurayda9293352015-03-23 15:57:13 -07006163static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6164 u16 opcode)
6165{
6166 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006167 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006168 struct mgmt_rp_remove_advertising rp;
6169
6170 BT_DBG("status %d", status);
6171
6172 hci_dev_lock(hdev);
6173
6174 /* A failure status here only means that we failed to disable
6175 * advertising. Otherwise, the advertising instance has been removed,
6176 * so report success.
6177 */
6178 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6179 if (!cmd)
6180 goto unlock;
6181
Florian Grandel01948332015-06-18 03:16:48 +02006182 cp = cmd->param;
6183 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006184
6185 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6186 &rp, sizeof(rp));
6187 mgmt_pending_remove(cmd);
6188
6189unlock:
6190 hci_dev_unlock(hdev);
6191}
6192
6193static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6194 void *data, u16 data_len)
6195{
6196 struct mgmt_cp_remove_advertising *cp = data;
6197 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006198 struct mgmt_pending_cmd *cmd;
6199 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006200 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006201
6202 BT_DBG("%s", hdev->name);
6203
Arman Ugurayda9293352015-03-23 15:57:13 -07006204 hci_dev_lock(hdev);
6205
Johan Hedberg952497b2015-06-18 21:05:31 +03006206 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006207 err = mgmt_cmd_status(sk, hdev->id,
6208 MGMT_OP_REMOVE_ADVERTISING,
6209 MGMT_STATUS_INVALID_PARAMS);
6210 goto unlock;
6211 }
6212
Arman Ugurayda9293352015-03-23 15:57:13 -07006213 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6214 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6215 pending_find(MGMT_OP_SET_LE, hdev)) {
6216 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6217 MGMT_STATUS_BUSY);
6218 goto unlock;
6219 }
6220
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006221 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006222 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6223 MGMT_STATUS_INVALID_PARAMS);
6224 goto unlock;
6225 }
6226
Florian Grandel01948332015-06-18 03:16:48 +02006227 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006228
Johan Hedberg37d3a1f2016-08-28 20:53:34 +03006229 hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006230
Florian Grandel01948332015-06-18 03:16:48 +02006231 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006232 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006233
Florian Grandel01948332015-06-18 03:16:48 +02006234 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6235 * flag is set or the device isn't powered then we have no HCI
6236 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006237 */
Florian Grandel01948332015-06-18 03:16:48 +02006238 if (skb_queue_empty(&req.cmd_q) ||
6239 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006240 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006241 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006242 err = mgmt_cmd_complete(sk, hdev->id,
6243 MGMT_OP_REMOVE_ADVERTISING,
6244 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6245 goto unlock;
6246 }
6247
6248 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6249 data_len);
6250 if (!cmd) {
6251 err = -ENOMEM;
6252 goto unlock;
6253 }
6254
Arman Ugurayda9293352015-03-23 15:57:13 -07006255 err = hci_req_run(&req, remove_advertising_complete);
6256 if (err < 0)
6257 mgmt_pending_remove(cmd);
6258
6259unlock:
6260 hci_dev_unlock(hdev);
6261
6262 return err;
6263}
6264
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006265static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6266{
6267 u8 max_len = HCI_MAX_AD_LENGTH;
6268
6269 if (is_adv_data) {
6270 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6271 MGMT_ADV_FLAG_LIMITED_DISCOV |
6272 MGMT_ADV_FLAG_MANAGED_FLAGS))
6273 max_len -= 3;
6274
6275 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6276 max_len -= 3;
6277 }
6278
6279 return max_len;
6280}
6281
6282static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6283 void *data, u16 data_len)
6284{
6285 struct mgmt_cp_get_adv_size_info *cp = data;
6286 struct mgmt_rp_get_adv_size_info rp;
6287 u32 flags, supported_flags;
6288 int err;
6289
6290 BT_DBG("%s", hdev->name);
6291
6292 if (!lmp_le_capable(hdev))
6293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6294 MGMT_STATUS_REJECTED);
6295
6296 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6297 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6298 MGMT_STATUS_INVALID_PARAMS);
6299
6300 flags = __le32_to_cpu(cp->flags);
6301
6302 /* The current implementation only supports a subset of the specified
6303 * flags.
6304 */
6305 supported_flags = get_supported_adv_flags(hdev);
6306 if (flags & ~supported_flags)
6307 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6308 MGMT_STATUS_INVALID_PARAMS);
6309
6310 rp.instance = cp->instance;
6311 rp.flags = cp->flags;
6312 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6313 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6314
6315 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6316 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6317
6318 return err;
6319}
6320
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006321static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006322 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006323 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006324 HCI_MGMT_NO_HDEV |
6325 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006326 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006327 HCI_MGMT_NO_HDEV |
6328 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006329 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006330 HCI_MGMT_NO_HDEV |
6331 HCI_MGMT_UNTRUSTED },
6332 { read_controller_info, MGMT_READ_INFO_SIZE,
6333 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006334 { set_powered, MGMT_SETTING_SIZE },
6335 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6336 { set_connectable, MGMT_SETTING_SIZE },
6337 { set_fast_connectable, MGMT_SETTING_SIZE },
6338 { set_bondable, MGMT_SETTING_SIZE },
6339 { set_link_security, MGMT_SETTING_SIZE },
6340 { set_ssp, MGMT_SETTING_SIZE },
6341 { set_hs, MGMT_SETTING_SIZE },
6342 { set_le, MGMT_SETTING_SIZE },
6343 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6344 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6345 { add_uuid, MGMT_ADD_UUID_SIZE },
6346 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006347 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6348 HCI_MGMT_VAR_LEN },
6349 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6350 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006351 { disconnect, MGMT_DISCONNECT_SIZE },
6352 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6353 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6354 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6355 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6356 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6357 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6358 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6359 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6360 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6361 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6362 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006363 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6364 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6365 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006366 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6367 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6368 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6369 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6370 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6371 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6372 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6373 { set_advertising, MGMT_SETTING_SIZE },
6374 { set_bredr, MGMT_SETTING_SIZE },
6375 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6376 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6377 { set_secure_conn, MGMT_SETTING_SIZE },
6378 { set_debug_keys, MGMT_SETTING_SIZE },
6379 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006380 { load_irks, MGMT_LOAD_IRKS_SIZE,
6381 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006382 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6383 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6384 { add_device, MGMT_ADD_DEVICE_SIZE },
6385 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006386 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6387 HCI_MGMT_VAR_LEN },
6388 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006389 HCI_MGMT_NO_HDEV |
6390 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006391 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006392 HCI_MGMT_UNCONFIGURED |
6393 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006394 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6395 HCI_MGMT_UNCONFIGURED },
6396 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6397 HCI_MGMT_UNCONFIGURED },
6398 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6399 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006400 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006401 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006402 HCI_MGMT_NO_HDEV |
6403 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006404 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006405 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6406 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006407 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006408 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006409 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006410 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6411 HCI_MGMT_UNTRUSTED },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006412};
6413
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006414void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006415{
Marcel Holtmannced85542015-03-14 19:27:56 -07006416 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006417
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006418 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6419 return;
6420
Marcel Holtmannf9207332015-03-14 19:27:55 -07006421 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006422 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006423 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6424 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6425 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006426 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006427 } else {
6428 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6429 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006430 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006431 }
6432 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006433 case HCI_AMP:
6434 ev.type = 0x02;
6435 break;
6436 default:
6437 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006438 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006439
6440 ev.bus = hdev->bus;
6441
6442 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6443 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006444}
6445
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006446void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006447{
Marcel Holtmannced85542015-03-14 19:27:56 -07006448 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006449 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006450
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006451 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6452 return;
6453
Marcel Holtmannf9207332015-03-14 19:27:55 -07006454 switch (hdev->dev_type) {
Marcel Holtmannca8bee52016-07-05 14:30:14 +02006455 case HCI_PRIMARY:
Marcel Holtmannf9207332015-03-14 19:27:55 -07006456 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006457
Marcel Holtmannf9207332015-03-14 19:27:55 -07006458 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6459 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6460 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006461 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006462 } else {
6463 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6464 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006465 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006466 }
6467 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006468 case HCI_AMP:
6469 ev.type = 0x02;
6470 break;
6471 default:
6472 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006473 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006474
6475 ev.bus = hdev->bus;
6476
6477 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6478 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006479}
6480
Andre Guedes6046dc32014-02-26 20:21:51 -03006481/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006482static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006483{
6484 struct hci_conn_params *p;
6485
6486 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006487 /* Needed for AUTO_OFF case where might not "really"
6488 * have been powered off.
6489 */
6490 list_del_init(&p->action);
6491
6492 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006493 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006494 case HCI_AUTO_CONN_ALWAYS:
6495 list_add(&p->action, &hdev->pend_le_conns);
6496 break;
6497 case HCI_AUTO_CONN_REPORT:
6498 list_add(&p->action, &hdev->pend_le_reports);
6499 break;
6500 default:
6501 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006502 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006503 }
6504}
6505
Johan Hedberg2ff13892015-11-25 16:15:44 +02006506void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006507{
6508 struct cmd_lookup match = { NULL, hdev };
6509
Johan Hedberg2ff13892015-11-25 16:15:44 +02006510 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006511
Johan Hedberg2ff13892015-11-25 16:15:44 +02006512 hci_dev_lock(hdev);
6513
6514 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006515 restart_le_actions(hdev);
6516 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006517 }
6518
Johan Hedberg229ab392013-03-15 17:06:53 -05006519 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6520
6521 new_settings(hdev, match.sk);
6522
Johan Hedberg229ab392013-03-15 17:06:53 -05006523 if (match.sk)
6524 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006525
6526 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006527}
6528
Johan Hedberg2ff13892015-11-25 16:15:44 +02006529void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006530{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006531 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006532 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006533
Johan Hedberg229ab392013-03-15 17:06:53 -05006534 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006535
6536 /* If the power off is because of hdev unregistration let
6537 * use the appropriate INVALID_INDEX status. Otherwise use
6538 * NOT_POWERED. We cover both scenarios here since later in
6539 * mgmt_index_removed() any hci_conn callbacks will have already
6540 * been triggered, potentially causing misleading DISCONNECTED
6541 * status responses.
6542 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006543 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006544 status = MGMT_STATUS_INVALID_INDEX;
6545 else
6546 status = MGMT_STATUS_NOT_POWERED;
6547
6548 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006549
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006550 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02006551 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6552 zero_cod, sizeof(zero_cod),
6553 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02006554 ext_info_changed(hdev, NULL);
6555 }
Johan Hedberg229ab392013-03-15 17:06:53 -05006556
Johan Hedberg2ff13892015-11-25 16:15:44 +02006557 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006558
6559 if (match.sk)
6560 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006561}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006562
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006563void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006564{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006565 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006566 u8 status;
6567
Johan Hedberg333ae952015-03-17 13:48:47 +02006568 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006569 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006570 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006571
6572 if (err == -ERFKILL)
6573 status = MGMT_STATUS_RFKILLED;
6574 else
6575 status = MGMT_STATUS_FAILED;
6576
Johan Hedberga69e8372015-03-06 21:08:53 +02006577 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006578
6579 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006580}
6581
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006582void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6583 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006584{
Johan Hedberg86742e12011-11-07 23:13:38 +02006585 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006586
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006587 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006588
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006589 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006590 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006591 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006592 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006593 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006594 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006595
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006596 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006597}
Johan Hedbergf7520542011-01-20 12:34:39 +02006598
Johan Hedbergd7b25452014-05-23 13:19:53 +03006599static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6600{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006601 switch (ltk->type) {
6602 case SMP_LTK:
6603 case SMP_LTK_SLAVE:
6604 if (ltk->authenticated)
6605 return MGMT_LTK_AUTHENTICATED;
6606 return MGMT_LTK_UNAUTHENTICATED;
6607 case SMP_LTK_P256:
6608 if (ltk->authenticated)
6609 return MGMT_LTK_P256_AUTH;
6610 return MGMT_LTK_P256_UNAUTH;
6611 case SMP_LTK_P256_DEBUG:
6612 return MGMT_LTK_P256_DEBUG;
6613 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006614
6615 return MGMT_LTK_UNAUTHENTICATED;
6616}
6617
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006618void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006619{
6620 struct mgmt_ev_new_long_term_key ev;
6621
6622 memset(&ev, 0, sizeof(ev));
6623
Marcel Holtmann5192d302014-02-19 17:11:58 -08006624 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006625 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006626 * to store long term keys. Their addresses will change the
6627 * next time around.
6628 *
6629 * Only when a remote device provides an identity address
6630 * make sure the long term key is stored. If the remote
6631 * identity is known, the long term keys are internally
6632 * mapped to the identity address. So allow static random
6633 * and public addresses here.
6634 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006635 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6636 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6637 ev.store_hint = 0x00;
6638 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006639 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006640
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006641 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006642 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006643 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006644 ev.key.enc_size = key->enc_size;
6645 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006646 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006647
Johan Hedberg2ceba532014-06-16 19:25:16 +03006648 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006649 ev.key.master = 1;
6650
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006651 /* Make sure we copy only the significant bytes based on the
6652 * encryption key size, and set the rest of the value to zeroes.
6653 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006654 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006655 memset(ev.key.val + key->enc_size, 0,
6656 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006657
Marcel Holtmann083368f2013-10-15 14:26:29 -07006658 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006659}
6660
Johan Hedbergcad20c22015-10-12 13:36:19 +02006661void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006662{
6663 struct mgmt_ev_new_irk ev;
6664
6665 memset(&ev, 0, sizeof(ev));
6666
Johan Hedbergcad20c22015-10-12 13:36:19 +02006667 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006668
Johan Hedberg95fbac82014-02-19 15:18:31 +02006669 bacpy(&ev.rpa, &irk->rpa);
6670 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6671 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6672 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6673
6674 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6675}
6676
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006677void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6678 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006679{
6680 struct mgmt_ev_new_csrk ev;
6681
6682 memset(&ev, 0, sizeof(ev));
6683
6684 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006685 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006686 * to store signature resolving keys. Their addresses will change
6687 * the next time around.
6688 *
6689 * Only when a remote device provides an identity address
6690 * make sure the signature resolving key is stored. So allow
6691 * static random and public addresses here.
6692 */
6693 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6694 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6695 ev.store_hint = 0x00;
6696 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006697 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006698
6699 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6700 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006701 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006702 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6703
6704 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6705}
6706
Andre Guedesffb5a8272014-07-01 18:10:11 -03006707void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006708 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6709 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006710{
6711 struct mgmt_ev_new_conn_param ev;
6712
Johan Hedbergc103aea2014-07-02 17:37:34 +03006713 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6714 return;
6715
Andre Guedesffb5a8272014-07-01 18:10:11 -03006716 memset(&ev, 0, sizeof(ev));
6717 bacpy(&ev.addr.bdaddr, bdaddr);
6718 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006719 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006720 ev.min_interval = cpu_to_le16(min_interval);
6721 ev.max_interval = cpu_to_le16(max_interval);
6722 ev.latency = cpu_to_le16(latency);
6723 ev.timeout = cpu_to_le16(timeout);
6724
6725 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6726}
6727
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006728void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6729 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006730{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006731 char buf[512];
6732 struct mgmt_ev_device_connected *ev = (void *) buf;
6733 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006734
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006735 bacpy(&ev->addr.bdaddr, &conn->dst);
6736 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006737
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006738 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006739
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006740 /* We must ensure that the EIR Data fields are ordered and
6741 * unique. Keep it simple for now and avoid the problem by not
6742 * adding any BR/EDR data to the LE adv.
6743 */
6744 if (conn->le_adv_data_len > 0) {
6745 memcpy(&ev->eir[eir_len],
6746 conn->le_adv_data, conn->le_adv_data_len);
6747 eir_len = conn->le_adv_data_len;
6748 } else {
6749 if (name_len > 0)
6750 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6751 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006752
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006753 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006754 eir_len = eir_append_data(ev->eir, eir_len,
6755 EIR_CLASS_OF_DEV,
6756 conn->dev_class, 3);
6757 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006758
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006759 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006760
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006761 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6762 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006763}
6764
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006765static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006766{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006767 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006768
Johan Hedbergf5818c22014-12-05 13:36:02 +02006769 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006770
6771 *sk = cmd->sk;
6772 sock_hold(*sk);
6773
Johan Hedberga664b5b2011-02-19 12:06:02 -03006774 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006775}
6776
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006777static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006778{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006779 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006780 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006781
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006782 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6783
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006784 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006785 mgmt_pending_remove(cmd);
6786}
6787
Johan Hedberg84c61d92014-08-01 11:13:30 +03006788bool mgmt_powering_down(struct hci_dev *hdev)
6789{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006790 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006791 struct mgmt_mode *cp;
6792
Johan Hedberg333ae952015-03-17 13:48:47 +02006793 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006794 if (!cmd)
6795 return false;
6796
6797 cp = cmd->param;
6798 if (!cp->val)
6799 return true;
6800
6801 return false;
6802}
6803
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006804void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006805 u8 link_type, u8 addr_type, u8 reason,
6806 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006807{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006808 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006809 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006810
Johan Hedberg84c61d92014-08-01 11:13:30 +03006811 /* The connection is still in hci_conn_hash so test for 1
6812 * instead of 0 to know if this is the last one.
6813 */
6814 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6815 cancel_delayed_work(&hdev->power_off);
6816 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006817 }
6818
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006819 if (!mgmt_connected)
6820 return;
6821
Andre Guedes57eb7762013-10-30 19:01:41 -03006822 if (link_type != ACL_LINK && link_type != LE_LINK)
6823 return;
6824
Johan Hedberg744cf192011-11-08 20:40:14 +02006825 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006826
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006827 bacpy(&ev.addr.bdaddr, bdaddr);
6828 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6829 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006830
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006831 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006832
6833 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006834 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006835
Johan Hedberg124f6e32012-02-09 13:50:12 +02006836 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006837 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006838}
6839
Marcel Holtmann78929242013-10-06 23:55:47 -07006840void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6841 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006842{
Andre Guedes3655bba2013-10-30 19:01:40 -03006843 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6844 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006845 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006846
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006847 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6848 hdev);
6849
Johan Hedberg333ae952015-03-17 13:48:47 +02006850 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006851 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006852 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006853
Andre Guedes3655bba2013-10-30 19:01:40 -03006854 cp = cmd->param;
6855
6856 if (bacmp(bdaddr, &cp->addr.bdaddr))
6857 return;
6858
6859 if (cp->addr.type != bdaddr_type)
6860 return;
6861
Johan Hedbergf5818c22014-12-05 13:36:02 +02006862 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006863 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006864}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006865
Marcel Holtmann445608d2013-10-06 23:55:48 -07006866void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6867 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006868{
6869 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006870
Johan Hedberg84c61d92014-08-01 11:13:30 +03006871 /* The connection is still in hci_conn_hash so test for 1
6872 * instead of 0 to know if this is the last one.
6873 */
6874 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6875 cancel_delayed_work(&hdev->power_off);
6876 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006877 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006878
Johan Hedberg4c659c32011-11-07 23:13:39 +02006879 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006880 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006881 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006882
Marcel Holtmann445608d2013-10-06 23:55:48 -07006883 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006884}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006885
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006886void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006887{
6888 struct mgmt_ev_pin_code_request ev;
6889
Johan Hedbergd8457692012-02-17 14:24:57 +02006890 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006891 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006892 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006893
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006894 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006895}
6896
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006897void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6898 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006899{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006900 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006901
Johan Hedberg333ae952015-03-17 13:48:47 +02006902 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006903 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006904 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006905
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006906 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006907 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006908}
6909
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006910void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6911 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006912{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006913 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006914
Johan Hedberg333ae952015-03-17 13:48:47 +02006915 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006916 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006917 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006918
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006919 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006920 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006921}
Johan Hedberga5c29682011-02-19 12:05:57 -03006922
Johan Hedberg744cf192011-11-08 20:40:14 +02006923int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006924 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006925 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006926{
6927 struct mgmt_ev_user_confirm_request ev;
6928
Johan Hedberg744cf192011-11-08 20:40:14 +02006929 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006930
Johan Hedberg272d90d2012-02-09 15:26:12 +02006931 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006932 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006933 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006934 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006935
Johan Hedberg744cf192011-11-08 20:40:14 +02006936 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006937 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006938}
6939
Johan Hedberg272d90d2012-02-09 15:26:12 +02006940int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006941 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08006942{
6943 struct mgmt_ev_user_passkey_request ev;
6944
6945 BT_DBG("%s", hdev->name);
6946
Johan Hedberg272d90d2012-02-09 15:26:12 +02006947 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006948 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08006949
6950 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006951 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08006952}
6953
Brian Gix0df4c182011-11-16 13:53:13 -08006954static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006955 u8 link_type, u8 addr_type, u8 status,
6956 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03006957{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006958 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03006959
Johan Hedberg333ae952015-03-17 13:48:47 +02006960 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03006961 if (!cmd)
6962 return -ENOENT;
6963
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006964 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006965 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03006966
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006967 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03006968}
6969
Johan Hedberg744cf192011-11-08 20:40:14 +02006970int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006971 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006972{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006973 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006974 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006975}
6976
Johan Hedberg272d90d2012-02-09 15:26:12 +02006977int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006978 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006979{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006980 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006981 status,
6982 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006983}
Johan Hedberg2a611692011-02-19 12:06:00 -03006984
Brian Gix604086b2011-11-23 08:28:33 -08006985int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006986 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006987{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006988 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006989 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006990}
6991
Johan Hedberg272d90d2012-02-09 15:26:12 +02006992int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006993 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006994{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006995 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006996 status,
6997 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006998}
6999
Johan Hedberg92a25252012-09-06 18:39:26 +03007000int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7001 u8 link_type, u8 addr_type, u32 passkey,
7002 u8 entered)
7003{
7004 struct mgmt_ev_passkey_notify ev;
7005
7006 BT_DBG("%s", hdev->name);
7007
7008 bacpy(&ev.addr.bdaddr, bdaddr);
7009 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7010 ev.passkey = __cpu_to_le32(passkey);
7011 ev.entered = entered;
7012
7013 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7014}
7015
Johan Hedberge1e930f2014-09-08 17:09:49 -07007016void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007017{
7018 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007019 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007020 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007021
Johan Hedberge1e930f2014-09-08 17:09:49 -07007022 bacpy(&ev.addr.bdaddr, &conn->dst);
7023 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7024 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007025
Johan Hedberge1e930f2014-09-08 17:09:49 -07007026 cmd = find_pairing(conn);
7027
7028 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7029 cmd ? cmd->sk : NULL);
7030
Johan Hedberga511b352014-12-11 21:45:45 +02007031 if (cmd) {
7032 cmd->cmd_complete(cmd, status);
7033 mgmt_pending_remove(cmd);
7034 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007035}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007036
Marcel Holtmann464996a2013-10-15 14:26:24 -07007037void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007038{
7039 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007040 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007041
7042 if (status) {
7043 u8 mgmt_err = mgmt_status(status);
7044 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007045 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007046 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007047 }
7048
Marcel Holtmann464996a2013-10-15 14:26:24 -07007049 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007050 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007051 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007052 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007053
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007054 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007055 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007056
Johan Hedberg47990ea2012-02-22 11:58:37 +02007057 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007058 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007059
7060 if (match.sk)
7061 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007062}
7063
Johan Hedberg890ea892013-03-15 17:06:52 -05007064static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007065{
Johan Hedberg890ea892013-03-15 17:06:52 -05007066 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007067 struct hci_cp_write_eir cp;
7068
Johan Hedberg976eb202012-10-24 21:12:01 +03007069 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007070 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007071
Johan Hedbergc80da272012-02-22 15:38:48 +02007072 memset(hdev->eir, 0, sizeof(hdev->eir));
7073
Johan Hedbergcacaf522012-02-21 00:52:42 +02007074 memset(&cp, 0, sizeof(cp));
7075
Johan Hedberg890ea892013-03-15 17:06:52 -05007076 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007077}
7078
Marcel Holtmann3e248562013-10-15 14:26:25 -07007079void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007080{
7081 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007082 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007083 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007084
7085 if (status) {
7086 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007087
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007088 if (enable && hci_dev_test_and_clear_flag(hdev,
7089 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007090 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007091 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007092 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007093
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007094 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7095 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007096 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007097 }
7098
7099 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007100 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007101 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007102 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007103 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007104 changed = hci_dev_test_and_clear_flag(hdev,
7105 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007106 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007107 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007108 }
7109
7110 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7111
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007112 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007113 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007114
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007115 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007116 sock_put(match.sk);
7117
Johan Hedberg890ea892013-03-15 17:06:52 -05007118 hci_req_init(&req, hdev);
7119
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007120 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7121 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007122 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7123 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007124 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007125 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007126 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007127 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007128
7129 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007130}
7131
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007132static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007133{
7134 struct cmd_lookup *match = data;
7135
Johan Hedberg90e70452012-02-23 23:09:40 +02007136 if (match->sk == NULL) {
7137 match->sk = cmd->sk;
7138 sock_hold(match->sk);
7139 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007140}
7141
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007142void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7143 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007144{
Johan Hedberg90e70452012-02-23 23:09:40 +02007145 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007146
Johan Hedberg92da6092013-03-15 17:06:55 -05007147 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7148 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7149 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007150
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007151 if (!status) {
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007152 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7153 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007154 ext_info_changed(hdev, NULL);
7155 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007156
7157 if (match.sk)
7158 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007159}
7160
Marcel Holtmann7667da32013-10-15 14:26:27 -07007161void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007162{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007163 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007164 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007165
Johan Hedberg13928972013-03-15 17:07:00 -05007166 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007167 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007168
7169 memset(&ev, 0, sizeof(ev));
7170 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007171 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007172
Johan Hedberg333ae952015-03-17 13:48:47 +02007173 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007174 if (!cmd) {
7175 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007176
Johan Hedberg13928972013-03-15 17:07:00 -05007177 /* If this is a HCI command related to powering on the
7178 * HCI dev don't send any mgmt signals.
7179 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007180 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007181 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007182 }
7183
Marcel Holtmann5504c3a2016-08-29 06:19:46 +02007184 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7185 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
Marcel Holtmann321c6fe2016-09-01 16:46:23 +02007186 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007187}
Szymon Jancc35938b2011-03-22 13:12:21 +01007188
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007189static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7190{
7191 int i;
7192
7193 for (i = 0; i < uuid_count; i++) {
7194 if (!memcmp(uuid, uuids[i], 16))
7195 return true;
7196 }
7197
7198 return false;
7199}
7200
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007201static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7202{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007203 u16 parsed = 0;
7204
7205 while (parsed < eir_len) {
7206 u8 field_len = eir[0];
7207 u8 uuid[16];
7208 int i;
7209
7210 if (field_len == 0)
7211 break;
7212
7213 if (eir_len - parsed < field_len + 1)
7214 break;
7215
7216 switch (eir[1]) {
7217 case EIR_UUID16_ALL:
7218 case EIR_UUID16_SOME:
7219 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007220 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007221 uuid[13] = eir[i + 3];
7222 uuid[12] = eir[i + 2];
7223 if (has_uuid(uuid, uuid_count, uuids))
7224 return true;
7225 }
7226 break;
7227 case EIR_UUID32_ALL:
7228 case EIR_UUID32_SOME:
7229 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007230 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007231 uuid[15] = eir[i + 5];
7232 uuid[14] = eir[i + 4];
7233 uuid[13] = eir[i + 3];
7234 uuid[12] = eir[i + 2];
7235 if (has_uuid(uuid, uuid_count, uuids))
7236 return true;
7237 }
7238 break;
7239 case EIR_UUID128_ALL:
7240 case EIR_UUID128_SOME:
7241 for (i = 0; i + 17 <= field_len; i += 16) {
7242 memcpy(uuid, eir + i + 2, 16);
7243 if (has_uuid(uuid, uuid_count, uuids))
7244 return true;
7245 }
7246 break;
7247 }
7248
7249 parsed += field_len + 1;
7250 eir += field_len + 1;
7251 }
7252
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007253 return false;
7254}
7255
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007256static void restart_le_scan(struct hci_dev *hdev)
7257{
7258 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007259 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007260 return;
7261
7262 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7263 hdev->discovery.scan_start +
7264 hdev->discovery.scan_duration))
7265 return;
7266
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007267 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007268 DISCOV_LE_RESTART_DELAY);
7269}
7270
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007271static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7272 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7273{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007274 /* If a RSSI threshold has been specified, and
7275 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7276 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7277 * is set, let it through for further processing, as we might need to
7278 * restart the scan.
7279 *
7280 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7281 * the results are also dropped.
7282 */
7283 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7284 (rssi == HCI_RSSI_INVALID ||
7285 (rssi < hdev->discovery.rssi &&
7286 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7287 return false;
7288
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007289 if (hdev->discovery.uuid_count != 0) {
7290 /* If a list of UUIDs is provided in filter, results with no
7291 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007292 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007293 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7294 hdev->discovery.uuids) &&
7295 !eir_has_uuids(scan_rsp, scan_rsp_len,
7296 hdev->discovery.uuid_count,
7297 hdev->discovery.uuids))
7298 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007299 }
7300
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007301 /* If duplicate filtering does not report RSSI changes, then restart
7302 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007303 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007304 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7305 restart_le_scan(hdev);
7306
7307 /* Validate RSSI value against the RSSI threshold once more. */
7308 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7309 rssi < hdev->discovery.rssi)
7310 return false;
7311 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007312
7313 return true;
7314}
7315
Marcel Holtmann901801b2013-10-06 23:55:51 -07007316void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007317 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7318 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007319{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007320 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007321 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007322 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007323
Johan Hedberg75ce2082014-07-02 22:42:01 +03007324 /* Don't send events for a non-kernel initiated discovery. With
7325 * LE one exception is if we have pend_le_reports > 0 in which
7326 * case we're doing passive scanning and want these events.
7327 */
7328 if (!hci_discovery_active(hdev)) {
7329 if (link_type == ACL_LINK)
7330 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007331 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007332 return;
7333 }
Andre Guedes12602d02013-04-30 15:29:40 -03007334
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007335 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007336 /* We are using service discovery */
7337 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7338 scan_rsp_len))
7339 return;
7340 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007341
Johan Hedberg78b781c2016-01-05 13:19:32 +02007342 if (hdev->discovery.limited) {
7343 /* Check for limited discoverable bit */
7344 if (dev_class) {
7345 if (!(dev_class[1] & 0x20))
7346 return;
7347 } else {
7348 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7349 if (!flags || !(flags[0] & LE_AD_LIMITED))
7350 return;
7351 }
7352 }
7353
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007354 /* Make sure that the buffer is big enough. The 5 extra bytes
7355 * are for the potential CoD field.
7356 */
7357 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007358 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007359
Johan Hedberg1dc06092012-01-15 21:01:23 +02007360 memset(buf, 0, sizeof(buf));
7361
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007362 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7363 * RSSI value was reported as 0 when not available. This behavior
7364 * is kept when using device discovery. This is required for full
7365 * backwards compatibility with the API.
7366 *
7367 * However when using service discovery, the value 127 will be
7368 * returned when the RSSI is not available.
7369 */
Szymon Janc91200e92015-01-22 16:57:05 +01007370 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7371 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007372 rssi = 0;
7373
Johan Hedberg841c5642014-07-07 12:45:54 +03007374 bacpy(&ev->addr.bdaddr, bdaddr);
7375 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007376 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007377 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007378
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007379 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007380 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007381 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007382
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007383 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7384 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007385 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007386 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007387
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007388 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007389 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007390 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007391
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007392 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7393 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007394
Marcel Holtmann901801b2013-10-06 23:55:51 -07007395 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007396}
Johan Hedberga88a9652011-03-30 13:18:12 +03007397
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007398void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7399 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007400{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007401 struct mgmt_ev_device_found *ev;
7402 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7403 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007404
Johan Hedbergb644ba32012-01-17 21:48:47 +02007405 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007406
Johan Hedbergb644ba32012-01-17 21:48:47 +02007407 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007408
Johan Hedbergb644ba32012-01-17 21:48:47 +02007409 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007410 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007411 ev->rssi = rssi;
7412
7413 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007414 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007415
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007416 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007417
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007418 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007419}
Johan Hedberg314b2382011-04-27 10:29:57 -04007420
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007421void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007422{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007423 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007424
Andre Guedes343fb142011-11-22 17:14:19 -03007425 BT_DBG("%s discovering %u", hdev->name, discovering);
7426
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007427 memset(&ev, 0, sizeof(ev));
7428 ev.type = hdev->discovery.type;
7429 ev.discovering = discovering;
7430
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007431 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007432}
Antti Julku5e762442011-08-25 16:48:02 +03007433
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007434static struct hci_mgmt_chan chan = {
7435 .channel = HCI_CHANNEL_CONTROL,
7436 .handler_count = ARRAY_SIZE(mgmt_handlers),
7437 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007438 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007439};
7440
7441int mgmt_init(void)
7442{
7443 return hci_mgmt_chan_register(&chan);
7444}
7445
7446void mgmt_exit(void)
7447{
7448 hci_mgmt_chan_unregister(&chan);
7449}