blob: 5a5089cb6570a33d0adf91565a536172ae84301e [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
Johan Hedberg71290692015-02-20 13:26:23 +020032#include <net/bluetooth/hci_sock.h>
Johan Hedberg4bc58f52014-05-20 09:45:47 +030033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070035
Johan Hedberg0857dd32014-12-19 13:40:20 +020036#include "hci_request.h"
Marcel Holtmannac4b7232013-10-10 14:54:16 -070037#include "smp.h"
Johan Hedberga380b6c2015-03-17 13:48:48 +020038#include "mgmt_util.h"
Johan Hedberg03811012010-12-08 00:21:06 +020039
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Johan Hedbergdc4270c2015-11-23 15:07:51 +020041#define MGMT_REVISION 11
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030050 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020051 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030082 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030083 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070084 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070085 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080086 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080087 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020088 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020089 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020090 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030091 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020092 MGMT_OP_ADD_DEVICE,
93 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030094 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020095 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020096 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020097 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020098 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010099 MGMT_OP_START_SERVICE_DISCOVERY,
Marcel Holtmann4f0f1552015-03-14 22:43:19 -0700100 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700101 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700102 MGMT_OP_READ_ADV_FEATURES,
Arman Uguray24b4f382015-03-23 15:57:12 -0700103 MGMT_OP_ADD_ADVERTISING,
Arman Ugurayda9293352015-03-23 15:57:13 -0700104 MGMT_OP_REMOVE_ADVERTISING,
Marcel Holtmann40b25fe2015-11-19 16:16:43 +0100105 MGMT_OP_GET_ADV_SIZE_INFO,
Johan Hedberg78b781c2016-01-05 13:19:32 +0200106 MGMT_OP_START_LIMITED_DISCOVERY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200107};
108
109static const u16 mgmt_events[] = {
110 MGMT_EV_CONTROLLER_ERROR,
111 MGMT_EV_INDEX_ADDED,
112 MGMT_EV_INDEX_REMOVED,
113 MGMT_EV_NEW_SETTINGS,
114 MGMT_EV_CLASS_OF_DEV_CHANGED,
115 MGMT_EV_LOCAL_NAME_CHANGED,
116 MGMT_EV_NEW_LINK_KEY,
117 MGMT_EV_NEW_LONG_TERM_KEY,
118 MGMT_EV_DEVICE_CONNECTED,
119 MGMT_EV_DEVICE_DISCONNECTED,
120 MGMT_EV_CONNECT_FAILED,
121 MGMT_EV_PIN_CODE_REQUEST,
122 MGMT_EV_USER_CONFIRM_REQUEST,
123 MGMT_EV_USER_PASSKEY_REQUEST,
124 MGMT_EV_AUTH_FAILED,
125 MGMT_EV_DEVICE_FOUND,
126 MGMT_EV_DISCOVERING,
127 MGMT_EV_DEVICE_BLOCKED,
128 MGMT_EV_DEVICE_UNBLOCKED,
129 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300130 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800131 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700132 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200133 MGMT_EV_DEVICE_ADDED,
134 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300135 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200136 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200137 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200138 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700139 MGMT_EV_EXT_INDEX_ADDED,
140 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700141 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700142 MGMT_EV_ADVERTISING_ADDED,
143 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200144};
145
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700146static const u16 mgmt_untrusted_commands[] = {
147 MGMT_OP_READ_INDEX_LIST,
148 MGMT_OP_READ_INFO,
149 MGMT_OP_READ_UNCONF_INDEX_LIST,
150 MGMT_OP_READ_CONFIG_INFO,
151 MGMT_OP_READ_EXT_INDEX_LIST,
152};
153
154static const u16 mgmt_untrusted_events[] = {
155 MGMT_EV_INDEX_ADDED,
156 MGMT_EV_INDEX_REMOVED,
157 MGMT_EV_NEW_SETTINGS,
158 MGMT_EV_CLASS_OF_DEV_CHANGED,
159 MGMT_EV_LOCAL_NAME_CHANGED,
160 MGMT_EV_UNCONF_INDEX_ADDED,
161 MGMT_EV_UNCONF_INDEX_REMOVED,
162 MGMT_EV_NEW_CONFIG_OPTIONS,
163 MGMT_EV_EXT_INDEX_ADDED,
164 MGMT_EV_EXT_INDEX_REMOVED,
165};
166
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800167#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200168
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200169#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
170 "\x00\x00\x00\x00\x00\x00\x00\x00"
171
Johan Hedbergca69b792011-11-11 18:10:00 +0200172/* HCI to MGMT error code conversion table */
173static u8 mgmt_status_table[] = {
174 MGMT_STATUS_SUCCESS,
175 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
176 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
177 MGMT_STATUS_FAILED, /* Hardware Failure */
178 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
179 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200180 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200181 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
182 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
183 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
184 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
185 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
186 MGMT_STATUS_BUSY, /* Command Disallowed */
187 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
188 MGMT_STATUS_REJECTED, /* Rejected Security */
189 MGMT_STATUS_REJECTED, /* Rejected Personal */
190 MGMT_STATUS_TIMEOUT, /* Host Timeout */
191 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
192 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
193 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
194 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
195 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
196 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
197 MGMT_STATUS_BUSY, /* Repeated Attempts */
198 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
199 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
200 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
201 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
202 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
203 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
204 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
205 MGMT_STATUS_FAILED, /* Unspecified Error */
206 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
207 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
208 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
209 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
210 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
211 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
212 MGMT_STATUS_FAILED, /* Unit Link Key Used */
213 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
214 MGMT_STATUS_TIMEOUT, /* Instant Passed */
215 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
216 MGMT_STATUS_FAILED, /* Transaction Collision */
217 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
218 MGMT_STATUS_REJECTED, /* QoS Rejected */
219 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
220 MGMT_STATUS_REJECTED, /* Insufficient Security */
221 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
222 MGMT_STATUS_BUSY, /* Role Switch Pending */
223 MGMT_STATUS_FAILED, /* Slot Violation */
224 MGMT_STATUS_FAILED, /* Role Switch Failed */
225 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
226 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
227 MGMT_STATUS_BUSY, /* Host Busy Pairing */
228 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
229 MGMT_STATUS_BUSY, /* Controller Busy */
230 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
231 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
232 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
233 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
234 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
235};
236
237static u8 mgmt_status(u8 hci_status)
238{
239 if (hci_status < ARRAY_SIZE(mgmt_status_table))
240 return mgmt_status_table[hci_status];
241
242 return MGMT_STATUS_FAILED;
243}
244
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700245static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
246 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700247{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700248 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
249 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700250}
251
Marcel Holtmann72000df2015-03-16 16:11:21 -0700252static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
253 u16 len, int flag, struct sock *skip_sk)
254{
255 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
256 flag, skip_sk);
257}
258
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700259static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
260 u16 len, struct sock *skip_sk)
261{
262 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
263 HCI_MGMT_GENERIC_EVENTS, skip_sk);
264}
265
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200266static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
267 struct sock *skip_sk)
268{
269 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700270 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200271}
272
Johan Hedberg85813a72015-10-21 18:02:59 +0300273static u8 le_addr_type(u8 mgmt_addr_type)
274{
275 if (mgmt_addr_type == BDADDR_LE_PUBLIC)
276 return ADDR_LE_DEV_PUBLIC;
277 else
278 return ADDR_LE_DEV_RANDOM;
279}
280
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300281static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
282 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200283{
284 struct mgmt_rp_read_version rp;
285
286 BT_DBG("sock %p", sk);
287
288 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700289 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200290
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200291 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
292 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200293}
294
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300295static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
296 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200297{
298 struct mgmt_rp_read_commands *rp;
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700299 u16 num_commands, num_events;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200300 size_t rp_size;
301 int i, err;
302
303 BT_DBG("sock %p", sk);
304
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700305 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
306 num_commands = ARRAY_SIZE(mgmt_commands);
307 num_events = ARRAY_SIZE(mgmt_events);
308 } else {
309 num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
310 num_events = ARRAY_SIZE(mgmt_untrusted_events);
311 }
312
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200313 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
314
315 rp = kmalloc(rp_size, GFP_KERNEL);
316 if (!rp)
317 return -ENOMEM;
318
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700319 rp->num_commands = cpu_to_le16(num_commands);
320 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200321
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700322 if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
323 __le16 *opcode = rp->opcodes;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200324
Marcel Holtmann99c679a2015-03-24 17:31:03 -0700325 for (i = 0; i < num_commands; i++, opcode++)
326 put_unaligned_le16(mgmt_commands[i], opcode);
327
328 for (i = 0; i < num_events; i++, opcode++)
329 put_unaligned_le16(mgmt_events[i], opcode);
330 } else {
331 __le16 *opcode = rp->opcodes;
332
333 for (i = 0; i < num_commands; i++, opcode++)
334 put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
335
336 for (i = 0; i < num_events; i++, opcode++)
337 put_unaligned_le16(mgmt_untrusted_events[i], opcode);
338 }
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200339
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200340 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
341 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200342 kfree(rp);
343
344 return err;
345}
346
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300347static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
348 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200351 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200352 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300354 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355
356 BT_DBG("sock %p", sk);
357
358 read_lock(&hci_dev_list_lock);
359
360 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300361 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200362 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700363 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700364 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200365 }
366
Johan Hedberga38528f2011-01-22 06:46:43 +0200367 rp_len = sizeof(*rp) + (2 * count);
368 rp = kmalloc(rp_len, GFP_ATOMIC);
369 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100370 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200371 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100372 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200373
Johan Hedberg476e44c2012-10-19 20:10:46 +0300374 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200375 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700376 if (hci_dev_test_flag(d, HCI_SETUP) ||
377 hci_dev_test_flag(d, HCI_CONFIG) ||
378 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379 continue;
380
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200381 /* Devices marked as raw-only are neither configured
382 * nor unconfigured controllers.
383 */
384 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700385 continue;
386
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200387 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700388 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700389 rp->index[count++] = cpu_to_le16(d->id);
390 BT_DBG("Added hci%u", d->id);
391 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200392 }
393
Johan Hedberg476e44c2012-10-19 20:10:46 +0300394 rp->num_controllers = cpu_to_le16(count);
395 rp_len = sizeof(*rp) + (2 * count);
396
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200397 read_unlock(&hci_dev_list_lock);
398
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200399 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
400 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200401
Johan Hedberga38528f2011-01-22 06:46:43 +0200402 kfree(rp);
403
404 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200405}
406
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200407static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
408 void *data, u16 data_len)
409{
410 struct mgmt_rp_read_unconf_index_list *rp;
411 struct hci_dev *d;
412 size_t rp_len;
413 u16 count;
414 int err;
415
416 BT_DBG("sock %p", sk);
417
418 read_lock(&hci_dev_list_lock);
419
420 count = 0;
421 list_for_each_entry(d, &hci_dev_list, list) {
422 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700423 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200424 count++;
425 }
426
427 rp_len = sizeof(*rp) + (2 * count);
428 rp = kmalloc(rp_len, GFP_ATOMIC);
429 if (!rp) {
430 read_unlock(&hci_dev_list_lock);
431 return -ENOMEM;
432 }
433
434 count = 0;
435 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700436 if (hci_dev_test_flag(d, HCI_SETUP) ||
437 hci_dev_test_flag(d, HCI_CONFIG) ||
438 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200439 continue;
440
441 /* Devices marked as raw-only are neither configured
442 * nor unconfigured controllers.
443 */
444 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
445 continue;
446
447 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700448 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200449 rp->index[count++] = cpu_to_le16(d->id);
450 BT_DBG("Added hci%u", d->id);
451 }
452 }
453
454 rp->num_controllers = cpu_to_le16(count);
455 rp_len = sizeof(*rp) + (2 * count);
456
457 read_unlock(&hci_dev_list_lock);
458
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200459 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
460 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200461
462 kfree(rp);
463
464 return err;
465}
466
Marcel Holtmann96f14742015-03-14 19:27:57 -0700467static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
468 void *data, u16 data_len)
469{
470 struct mgmt_rp_read_ext_index_list *rp;
471 struct hci_dev *d;
472 size_t rp_len;
473 u16 count;
474 int err;
475
476 BT_DBG("sock %p", sk);
477
478 read_lock(&hci_dev_list_lock);
479
480 count = 0;
481 list_for_each_entry(d, &hci_dev_list, list) {
482 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
483 count++;
484 }
485
486 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
487 rp = kmalloc(rp_len, GFP_ATOMIC);
488 if (!rp) {
489 read_unlock(&hci_dev_list_lock);
490 return -ENOMEM;
491 }
492
493 count = 0;
494 list_for_each_entry(d, &hci_dev_list, list) {
495 if (hci_dev_test_flag(d, HCI_SETUP) ||
496 hci_dev_test_flag(d, HCI_CONFIG) ||
497 hci_dev_test_flag(d, HCI_USER_CHANNEL))
498 continue;
499
500 /* Devices marked as raw-only are neither configured
501 * nor unconfigured controllers.
502 */
503 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
504 continue;
505
506 if (d->dev_type == HCI_BREDR) {
507 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
508 rp->entry[count].type = 0x01;
509 else
510 rp->entry[count].type = 0x00;
511 } else if (d->dev_type == HCI_AMP) {
512 rp->entry[count].type = 0x02;
513 } else {
514 continue;
515 }
516
517 rp->entry[count].bus = d->bus;
518 rp->entry[count++].index = cpu_to_le16(d->id);
519 BT_DBG("Added hci%u", d->id);
520 }
521
522 rp->num_controllers = cpu_to_le16(count);
523 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
524
525 read_unlock(&hci_dev_list_lock);
526
527 /* If this command is called at least once, then all the
528 * default index and unconfigured index events are disabled
529 * and from now on only extended index events are used.
530 */
531 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
532 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
533 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
534
535 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
536 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
537
538 kfree(rp);
539
540 return err;
541}
542
Marcel Holtmanndbece372014-07-04 18:11:55 +0200543static bool is_configured(struct hci_dev *hdev)
544{
545 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700546 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200547 return false;
548
549 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
550 !bacmp(&hdev->public_addr, BDADDR_ANY))
551 return false;
552
553 return true;
554}
555
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200556static __le32 get_missing_options(struct hci_dev *hdev)
557{
558 u32 options = 0;
559
Marcel Holtmanndbece372014-07-04 18:11:55 +0200560 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700561 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200562 options |= MGMT_OPTION_EXTERNAL_CONFIG;
563
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200564 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
565 !bacmp(&hdev->public_addr, BDADDR_ANY))
566 options |= MGMT_OPTION_PUBLIC_ADDRESS;
567
568 return cpu_to_le32(options);
569}
570
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200571static int new_options(struct hci_dev *hdev, struct sock *skip)
572{
573 __le32 options = get_missing_options(hdev);
574
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700575 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
576 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200577}
578
Marcel Holtmanndbece372014-07-04 18:11:55 +0200579static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
580{
581 __le32 options = get_missing_options(hdev);
582
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200583 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
584 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200585}
586
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200587static int read_config_info(struct sock *sk, struct hci_dev *hdev,
588 void *data, u16 data_len)
589{
590 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200591 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200592
593 BT_DBG("sock %p %s", sk, hdev->name);
594
595 hci_dev_lock(hdev);
596
597 memset(&rp, 0, sizeof(rp));
598 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200599
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200600 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
601 options |= MGMT_OPTION_EXTERNAL_CONFIG;
602
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200603 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200604 options |= MGMT_OPTION_PUBLIC_ADDRESS;
605
606 rp.supported_options = cpu_to_le32(options);
607 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200608
609 hci_dev_unlock(hdev);
610
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200611 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
612 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200613}
614
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200615static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200616{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200617 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200618
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200619 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300620 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800621 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300622 settings |= MGMT_SETTING_CONNECTABLE;
623 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200624
Andre Guedesed3fa312012-07-24 15:03:46 -0300625 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500626 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
627 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200628 settings |= MGMT_SETTING_BREDR;
629 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700630
631 if (lmp_ssp_capable(hdev)) {
632 settings |= MGMT_SETTING_SSP;
633 settings |= MGMT_SETTING_HS;
634 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800635
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800636 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800637 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700638 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100639
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300640 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200641 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300642 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300643 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200644 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800645 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300646 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200647
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200648 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
649 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200650 settings |= MGMT_SETTING_CONFIGURATION;
651
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200652 return settings;
653}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200654
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200655static u32 get_current_settings(struct hci_dev *hdev)
656{
657 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200658
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200659 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100660 settings |= MGMT_SETTING_POWERED;
661
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700662 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200663 settings |= MGMT_SETTING_CONNECTABLE;
664
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700665 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500666 settings |= MGMT_SETTING_FAST_CONNECTABLE;
667
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700668 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669 settings |= MGMT_SETTING_DISCOVERABLE;
670
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700671 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300672 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200673
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700674 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200675 settings |= MGMT_SETTING_BREDR;
676
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700677 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200678 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200679
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700680 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200681 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200682
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700683 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200684 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200685
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700686 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200687 settings |= MGMT_SETTING_HS;
688
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700689 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300690 settings |= MGMT_SETTING_ADVERTISING;
691
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700692 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800693 settings |= MGMT_SETTING_SECURE_CONN;
694
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700695 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800696 settings |= MGMT_SETTING_DEBUG_KEYS;
697
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700698 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200699 settings |= MGMT_SETTING_PRIVACY;
700
Marcel Holtmann93690c22015-03-06 10:11:21 -0800701 /* The current setting for static address has two purposes. The
702 * first is to indicate if the static address will be used and
703 * the second is to indicate if it is actually set.
704 *
705 * This means if the static address is not configured, this flag
Marcel Holtmann08dc0e92015-03-25 18:32:13 -0700706 * will never be set. If the address is configured, then if the
Marcel Holtmann93690c22015-03-06 10:11:21 -0800707 * address is actually used decides if the flag is set or not.
708 *
709 * For single mode LE only controllers and dual-mode controllers
710 * with BR/EDR disabled, the existence of the static address will
711 * be evaluated.
712 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700713 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700714 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800715 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
716 if (bacmp(&hdev->static_addr, BDADDR_ANY))
717 settings |= MGMT_SETTING_STATIC_ADDRESS;
718 }
719
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200720 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200721}
722
Johan Hedberg333ae952015-03-17 13:48:47 +0200723static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
724{
725 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
726}
727
Johan Hedberg333ae952015-03-17 13:48:47 +0200728static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
729 struct hci_dev *hdev,
730 const void *data)
731{
732 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
733}
734
Johan Hedbergf2252572015-11-18 12:49:20 +0200735u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
Johan Hedberg9a43e252013-10-20 19:00:07 +0300736{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200737 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300738
739 /* If there's a pending mgmt command the flags will not yet have
740 * their final values, so check for this first.
741 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200742 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300743 if (cmd) {
744 struct mgmt_mode *cp = cmd->param;
745 if (cp->val == 0x01)
746 return LE_AD_GENERAL;
747 else if (cp->val == 0x02)
748 return LE_AD_LIMITED;
749 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700750 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300751 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700752 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300753 return LE_AD_GENERAL;
754 }
755
756 return 0;
757}
758
Johan Hedbergf2252572015-11-18 12:49:20 +0200759bool mgmt_get_connectable(struct hci_dev *hdev)
Arman Uguraye7a685d2015-03-25 18:53:40 -0700760{
761 struct mgmt_pending_cmd *cmd;
762
763 /* If there's a pending mgmt command the flag will not yet have
764 * it's final value, so check for this first.
765 */
766 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
767 if (cmd) {
768 struct mgmt_mode *cp = cmd->param;
769
770 return cp->val;
771 }
772
773 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
774}
775
Johan Hedberg7d785252011-12-15 00:47:39 +0200776static void service_cache_off(struct work_struct *work)
777{
778 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300779 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500780 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200781
Marcel Holtmanna69d8922015-03-13 02:11:05 -0700782 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +0200783 return;
784
Johan Hedberg890ea892013-03-15 17:06:52 -0500785 hci_req_init(&req, hdev);
786
Johan Hedberg7d785252011-12-15 00:47:39 +0200787 hci_dev_lock(hdev);
788
Johan Hedbergb1a89172015-11-25 16:15:42 +0200789 __hci_req_update_eir(&req);
Johan Hedberg14bf5ea2015-11-22 19:00:22 +0200790 __hci_req_update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200791
792 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500793
794 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200795}
796
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200797static void rpa_expired(struct work_struct *work)
798{
799 struct hci_dev *hdev = container_of(work, struct hci_dev,
800 rpa_expired.work);
801 struct hci_request req;
802
803 BT_DBG("");
804
Marcel Holtmanna1536da2015-03-13 02:11:01 -0700805 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200806
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700807 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200808 return;
809
810 /* The generation of a new RPA and programming it into the
Johan Hedbergf2252572015-11-18 12:49:20 +0200811 * controller happens in the hci_req_enable_advertising()
812 * function.
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200813 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200814 hci_req_init(&req, hdev);
Johan Hedbergf2252572015-11-18 12:49:20 +0200815 __hci_req_enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200816 hci_req_run(&req, NULL);
817}
818
Johan Hedberg6a919082012-02-28 06:17:26 +0200819static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200820{
Marcel Holtmann238be782015-03-13 02:11:06 -0700821 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +0200822 return;
823
Johan Hedberg4f87da82012-03-02 19:55:56 +0200824 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200825 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200826
Johan Hedberg4f87da82012-03-02 19:55:56 +0200827 /* Non-mgmt controlled devices get this bit set
828 * implicitly so that pairing works for them, however
829 * for mgmt we require user-space to explicitly enable
830 * it
831 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -0700832 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +0200833}
834
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200835static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300836 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200837{
838 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200839
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200840 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200841
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300842 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200843
Johan Hedberg03811012010-12-08 00:21:06 +0200844 memset(&rp, 0, sizeof(rp));
845
Johan Hedberg03811012010-12-08 00:21:06 +0200846 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200847
848 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200849 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200850
851 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
852 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
853
854 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200855
856 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200857 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200858
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300859 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200860
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200861 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
862 sizeof(rp));
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200863}
864
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200865static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200866{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200867 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200868
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200869 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
870 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200871}
872
Marcel Holtmann1904a852015-01-11 13:50:44 -0800873static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +0200874{
875 BT_DBG("%s status 0x%02x", hdev->name, status);
876
Johan Hedberga3172b72014-02-28 09:33:44 +0200877 if (hci_conn_count(hdev) == 0) {
878 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200879 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +0200880 }
Johan Hedberg8b064a32014-02-24 14:52:22 +0200881}
882
Johan Hedbergf2252572015-11-18 12:49:20 +0200883void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700884{
885 struct mgmt_ev_advertising_added ev;
886
887 ev.instance = instance;
888
889 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
890}
891
Johan Hedbergf2252572015-11-18 12:49:20 +0200892void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
893 u8 instance)
Arman Uguray912098a2015-03-23 15:57:15 -0700894{
895 struct mgmt_ev_advertising_removed ev;
896
897 ev.instance = instance;
898
899 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
900}
901
Florian Grandel7816b822015-06-18 03:16:45 +0200902static void cancel_adv_timeout(struct hci_dev *hdev)
903{
904 if (hdev->adv_instance_timeout) {
905 hdev->adv_instance_timeout = 0;
906 cancel_delayed_work(&hdev->adv_instance_expire);
907 }
908}
909
Johan Hedberg8b064a32014-02-24 14:52:22 +0200910static int clean_up_hci_state(struct hci_dev *hdev)
911{
912 struct hci_request req;
913 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +0300914 bool discov_stopped;
915 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200916
917 hci_req_init(&req, hdev);
918
919 if (test_bit(HCI_ISCAN, &hdev->flags) ||
920 test_bit(HCI_PSCAN, &hdev->flags)) {
921 u8 scan = 0x00;
922 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
923 }
924
Johan Hedbergf2252572015-11-18 12:49:20 +0200925 hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
Arman Uguray912098a2015-03-23 15:57:15 -0700926
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700927 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +0200928 __hci_req_disable_advertising(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200929
Johan Hedberg2154d3f2015-11-11 08:30:45 +0200930 discov_stopped = hci_req_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200931
932 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
Johan Hedberg89e0ccc2015-10-22 10:49:38 +0300933 /* 0x15 == Terminated due to Power Off */
934 __hci_abort_conn(&req, conn, 0x15);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200935 }
936
Johan Hedberg23a48092014-07-08 16:05:06 +0300937 err = hci_req_run(&req, clean_up_hci_complete);
938 if (!err && discov_stopped)
939 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
940
941 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +0200942}
943
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200944static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300945 u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300947 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200948 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200949 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200950
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200951 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200952
Johan Hedberga7e80f22013-01-09 16:05:19 +0200953 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +0200954 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
955 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +0200956
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300957 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200958
Johan Hedberg333ae952015-03-17 13:48:47 +0200959 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +0200960 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
961 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300962 goto failed;
963 }
964
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200965 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200966 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200967 goto failed;
968 }
969
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200970 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
971 if (!cmd) {
972 err = -ENOMEM;
973 goto failed;
974 }
975
Johan Hedberg8b064a32014-02-24 14:52:22 +0200976 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +0200977 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200978 err = 0;
979 } else {
980 /* Disconnect connections, stop scans, etc */
981 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +0200982 if (!err)
983 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
984 HCI_POWER_OFF_TIMEOUT);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200985
Johan Hedberg8b064a32014-02-24 14:52:22 +0200986 /* ENODATA means there were no HCI commands queued */
987 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +0200988 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +0200989 queue_work(hdev->req_workqueue, &hdev->power_off.work);
990 err = 0;
991 }
992 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993
994failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300995 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996 return err;
997}
998
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200999static int new_settings(struct hci_dev *hdev, struct sock *skip)
1000{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001001 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001002
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001003 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1004 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001005}
1006
Johan Hedberg91a668b2014-07-09 13:28:26 +03001007int mgmt_new_settings(struct hci_dev *hdev)
1008{
1009 return new_settings(hdev, NULL);
1010}
1011
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001012struct cmd_lookup {
1013 struct sock *sk;
1014 struct hci_dev *hdev;
1015 u8 mgmt_status;
1016};
1017
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001018static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001019{
1020 struct cmd_lookup *match = data;
1021
1022 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1023
1024 list_del(&cmd->list);
1025
1026 if (match->sk == NULL) {
1027 match->sk = cmd->sk;
1028 sock_hold(match->sk);
1029 }
1030
1031 mgmt_pending_free(cmd);
1032}
1033
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001034static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001035{
1036 u8 *status = data;
1037
Johan Hedberga69e8372015-03-06 21:08:53 +02001038 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001039 mgmt_pending_remove(cmd);
1040}
1041
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001042static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001043{
1044 if (cmd->cmd_complete) {
1045 u8 *status = data;
1046
1047 cmd->cmd_complete(cmd, *status);
1048 mgmt_pending_remove(cmd);
1049
1050 return;
1051 }
1052
1053 cmd_status_rsp(cmd, data);
1054}
1055
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001056static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001057{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001058 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1059 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001060}
1061
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001062static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001063{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001064 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1065 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001066}
1067
Johan Hedberge6fe7982013-10-02 15:45:22 +03001068static u8 mgmt_bredr_support(struct hci_dev *hdev)
1069{
1070 if (!lmp_bredr_capable(hdev))
1071 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001072 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001073 return MGMT_STATUS_REJECTED;
1074 else
1075 return MGMT_STATUS_SUCCESS;
1076}
1077
1078static u8 mgmt_le_support(struct hci_dev *hdev)
1079{
1080 if (!lmp_le_capable(hdev))
1081 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001082 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001083 return MGMT_STATUS_REJECTED;
1084 else
1085 return MGMT_STATUS_SUCCESS;
1086}
1087
Johan Hedbergaed1a882015-11-22 17:24:44 +03001088void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001089{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001090 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001091
1092 BT_DBG("status 0x%02x", status);
1093
1094 hci_dev_lock(hdev);
1095
Johan Hedberg333ae952015-03-17 13:48:47 +02001096 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001097 if (!cmd)
1098 goto unlock;
1099
1100 if (status) {
1101 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001102 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001103 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001104 goto remove_cmd;
1105 }
1106
Johan Hedbergaed1a882015-11-22 17:24:44 +03001107 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1108 hdev->discov_timeout > 0) {
1109 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1110 queue_delayed_work(hdev->req_workqueue, &hdev->discov_off, to);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001111 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001112
1113 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergaed1a882015-11-22 17:24:44 +03001114 new_settings(hdev, cmd->sk);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001115
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001116remove_cmd:
1117 mgmt_pending_remove(cmd);
1118
1119unlock:
1120 hci_dev_unlock(hdev);
1121}
1122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001123static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001124 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001125{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001126 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001127 struct mgmt_pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001128 u16 timeout;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001129 int err;
1130
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001131 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001132
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001133 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1134 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001135 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1136 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001137
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001138 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001139 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1140 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001141
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001142 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001143
1144 /* Disabling discoverable requires that no timeout is set,
1145 * and enabling limited discoverable requires a timeout.
1146 */
1147 if ((cp->val == 0x00 && timeout > 0) ||
1148 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001149 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1150 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001151
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001152 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001153
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001154 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001155 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1156 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001157 goto failed;
1158 }
1159
Johan Hedberg333ae952015-03-17 13:48:47 +02001160 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1161 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001162 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1163 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 goto failed;
1165 }
1166
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001167 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001168 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1169 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001170 goto failed;
1171 }
1172
1173 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001174 bool changed = false;
1175
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001176 /* Setting limited discoverable when powered off is
1177 * not a valid operation since it requires a timeout
1178 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1179 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001180 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001181 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001182 changed = true;
1183 }
1184
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001185 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001186 if (err < 0)
1187 goto failed;
1188
1189 if (changed)
1190 err = new_settings(hdev, sk);
1191
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001192 goto failed;
1193 }
1194
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001195 /* If the current mode is the same, then just update the timeout
1196 * value with the new value. And if only the timeout gets updated,
1197 * then no need for any HCI transactions.
1198 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001199 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1200 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1201 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001202 cancel_delayed_work(&hdev->discov_off);
1203 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001204
Marcel Holtmann36261542013-10-15 08:28:51 -07001205 if (cp->val && hdev->discov_timeout > 0) {
1206 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Johan Hedbergc366f552015-11-23 15:43:06 +02001207 queue_delayed_work(hdev->req_workqueue,
1208 &hdev->discov_off, to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001209 }
1210
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001211 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001212 goto failed;
1213 }
1214
1215 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1216 if (!cmd) {
1217 err = -ENOMEM;
1218 goto failed;
1219 }
1220
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001221 /* Cancel any potential discoverable timeout that might be
1222 * still active and store new timeout value. The arming of
1223 * the timeout happens in the complete handler.
1224 */
1225 cancel_delayed_work(&hdev->discov_off);
1226 hdev->discov_timeout = timeout;
1227
Johan Hedbergaed1a882015-11-22 17:24:44 +03001228 if (cp->val)
1229 hci_dev_set_flag(hdev, HCI_DISCOVERABLE);
1230 else
1231 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1232
Johan Hedbergb456f872013-10-19 23:38:22 +03001233 /* Limited discoverable mode */
1234 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001235 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001236 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001237 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001238
Johan Hedbergaed1a882015-11-22 17:24:44 +03001239 queue_work(hdev->req_workqueue, &hdev->discoverable_update);
1240 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001241
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001242failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001243 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001244 return err;
1245}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001246
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001247void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001248{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001249 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001250
1251 BT_DBG("status 0x%02x", status);
1252
1253 hci_dev_lock(hdev);
1254
Johan Hedberg333ae952015-03-17 13:48:47 +02001255 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001256 if (!cmd)
1257 goto unlock;
1258
Johan Hedberg37438c12013-10-14 16:20:05 +03001259 if (status) {
1260 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001261 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001262 goto remove_cmd;
1263 }
1264
Johan Hedberg2b76f452013-03-15 17:07:04 -05001265 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001266 new_settings(hdev, cmd->sk);
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001267
Johan Hedberg37438c12013-10-14 16:20:05 +03001268remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001269 mgmt_pending_remove(cmd);
1270
1271unlock:
1272 hci_dev_unlock(hdev);
1273}
1274
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001275static int set_connectable_update_settings(struct hci_dev *hdev,
1276 struct sock *sk, u8 val)
1277{
1278 bool changed = false;
1279 int err;
1280
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001281 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001282 changed = true;
1283
1284 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001285 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001286 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001287 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1288 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001289 }
1290
1291 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1292 if (err < 0)
1293 return err;
1294
Johan Hedberg562064e2014-07-08 16:35:34 +03001295 if (changed) {
Johan Hedberg01b1cb82015-11-16 12:52:21 +02001296 hci_req_update_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001297 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001298 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001299 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001300
1301 return 0;
1302}
1303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001304static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001305 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001306{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001307 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001308 struct mgmt_pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001309 int err;
1310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001311 BT_DBG("request for %s", hdev->name);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001312
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001313 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1314 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001315 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1316 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001317
Johan Hedberga7e80f22013-01-09 16:05:19 +02001318 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001319 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1320 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001321
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001322 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001323
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001324 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001325 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001326 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001327 }
1328
Johan Hedberg333ae952015-03-17 13:48:47 +02001329 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1330 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001331 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1332 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001333 goto failed;
1334 }
1335
Johan Hedberg73f22f62010-12-29 16:00:25 +02001336 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1337 if (!cmd) {
1338 err = -ENOMEM;
Johan Hedberg72a734e2010-12-30 00:38:22 +02001339 goto failed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001340 }
1341
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001342 if (cp->val) {
1343 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1344 } else {
1345 if (hdev->discov_timeout > 0)
1346 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001347
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001348 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1349 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1350 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg9b742462013-10-14 16:20:03 +03001351 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001352
Johan Hedberg53c0ba72015-11-22 16:43:43 +03001353 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1354 err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001355
1356failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001357 hci_dev_unlock(hdev);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001358 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001359}
1360
Johan Hedbergb2939472014-07-30 09:22:23 +03001361static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001362 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001363{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001364 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001365 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001366 int err;
1367
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001368 BT_DBG("request for %s", hdev->name);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001369
Johan Hedberga7e80f22013-01-09 16:05:19 +02001370 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001371 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1372 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001373
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001374 hci_dev_lock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001375
1376 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001377 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001378 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001379 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg053f0212011-01-26 13:07:10 +02001380
Johan Hedbergb2939472014-07-30 09:22:23 +03001381 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001382 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001383 goto unlock;
Johan Hedberg053f0212011-01-26 13:07:10 +02001384
Marcel Holtmann55594352013-10-06 16:11:57 -07001385 if (changed)
1386 err = new_settings(hdev, sk);
Johan Hedberg053f0212011-01-26 13:07:10 +02001387
Marcel Holtmann55594352013-10-06 16:11:57 -07001388unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001389 hci_dev_unlock(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +02001390 return err;
1391}
1392
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001393static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1394 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001395{
1396 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001397 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001398 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001399 int err;
1400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001401 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001402
Johan Hedberge6fe7982013-10-02 15:45:22 +03001403 status = mgmt_bredr_support(hdev);
1404 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001405 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1406 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001407
Johan Hedberga7e80f22013-01-09 16:05:19 +02001408 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001409 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1410 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001411
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001412 hci_dev_lock(hdev);
1413
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001414 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001415 bool changed = false;
1416
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001417 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001418 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001419 changed = true;
1420 }
1421
1422 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1423 if (err < 0)
1424 goto failed;
1425
1426 if (changed)
1427 err = new_settings(hdev, sk);
1428
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001429 goto failed;
1430 }
1431
Johan Hedberg333ae952015-03-17 13:48:47 +02001432 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001433 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1434 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001435 goto failed;
1436 }
1437
1438 val = !!cp->val;
1439
1440 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1441 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1442 goto failed;
1443 }
1444
1445 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1446 if (!cmd) {
1447 err = -ENOMEM;
1448 goto failed;
1449 }
1450
1451 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1452 if (err < 0) {
1453 mgmt_pending_remove(cmd);
1454 goto failed;
1455 }
1456
1457failed:
1458 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001459 return err;
1460}
1461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001463{
1464 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001465 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001466 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001467 int err;
1468
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001469 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001470
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001471 status = mgmt_bredr_support(hdev);
1472 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001473 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001474
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001475 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001476 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1477 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001478
Johan Hedberga7e80f22013-01-09 16:05:19 +02001479 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001480 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1481 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001482
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001483 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001484
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001485 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001486 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001487
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001488 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001489 changed = !hci_dev_test_and_set_flag(hdev,
1490 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001491 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001492 changed = hci_dev_test_and_clear_flag(hdev,
1493 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001494 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001495 changed = hci_dev_test_and_clear_flag(hdev,
1496 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001497 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001498 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001499 }
1500
1501 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1502 if (err < 0)
1503 goto failed;
1504
1505 if (changed)
1506 err = new_settings(hdev, sk);
1507
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001508 goto failed;
1509 }
1510
Johan Hedberg333ae952015-03-17 13:48:47 +02001511 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001512 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1513 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001514 goto failed;
1515 }
1516
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001517 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001518 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1519 goto failed;
1520 }
1521
1522 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1523 if (!cmd) {
1524 err = -ENOMEM;
1525 goto failed;
1526 }
1527
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001528 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03001529 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
1530 sizeof(cp->val), &cp->val);
1531
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001532 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001533 if (err < 0) {
1534 mgmt_pending_remove(cmd);
1535 goto failed;
1536 }
1537
1538failed:
1539 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001540 return err;
1541}
1542
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001544{
1545 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001546 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001547 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001548 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001551
Johan Hedberge6fe7982013-10-02 15:45:22 +03001552 status = mgmt_bredr_support(hdev);
1553 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001554 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001555
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001556 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001557 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1558 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001559
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001560 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001561 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1562 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001563
Johan Hedberga7e80f22013-01-09 16:05:19 +02001564 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1566 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001567
Marcel Holtmannee392692013-10-01 22:59:23 -07001568 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001569
Johan Hedberg333ae952015-03-17 13:48:47 +02001570 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001571 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1572 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02001573 goto unlock;
1574 }
1575
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001576 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001577 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001578 } else {
1579 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001580 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1581 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001582 goto unlock;
1583 }
1584
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001585 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001586 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001587
1588 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1589 if (err < 0)
1590 goto unlock;
1591
1592 if (changed)
1593 err = new_settings(hdev, sk);
1594
1595unlock:
1596 hci_dev_unlock(hdev);
1597 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001598}
1599
Marcel Holtmann1904a852015-01-11 13:50:44 -08001600static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001601{
1602 struct cmd_lookup match = { NULL, hdev };
1603
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301604 hci_dev_lock(hdev);
1605
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001606 if (status) {
1607 u8 mgmt_err = mgmt_status(status);
1608
1609 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1610 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301611 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001612 }
1613
1614 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1615
1616 new_settings(hdev, match.sk);
1617
1618 if (match.sk)
1619 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001620
1621 /* Make sure the controller has a good default for
1622 * advertising data. Restrict the update to when LE
1623 * has actually been enabled. During power on, the
1624 * update in powered_update_hci will take care of it.
1625 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001626 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001627 struct hci_request req;
1628
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001629 hci_req_init(&req, hdev);
Johan Hedbergcab054a2015-11-30 11:21:45 +02001630 __hci_req_update_adv_data(&req, 0x00);
1631 __hci_req_update_scan_rsp_data(&req, 0x00);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001632 hci_req_run(&req, NULL);
Johan Hedberg2e93e532015-11-11 08:11:17 +02001633 hci_update_background_scan(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001634 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05301635
1636unlock:
1637 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001638}
1639
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001640static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001641{
1642 struct mgmt_mode *cp = data;
1643 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001644 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001645 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001646 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001647 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001648
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001649 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001650
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001651 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001652 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1653 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001654
Johan Hedberga7e80f22013-01-09 16:05:19 +02001655 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001656 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1657 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001658
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001659 /* Bluetooth single mode LE only controllers or dual-mode
1660 * controllers configured as LE only devices, do not allow
1661 * switching LE off. These have either LE enabled explicitly
1662 * or BR/EDR has been previously switched off.
1663 *
1664 * When trying to enable an already enabled LE, then gracefully
1665 * send a positive response. Trying to disable it however will
1666 * result into rejection.
1667 */
1668 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1669 if (cp->val == 0x01)
1670 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1671
Johan Hedberga69e8372015-03-06 21:08:53 +02001672 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1673 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07001674 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03001675
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001676 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001677
1678 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001679 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001680
Florian Grandel847818d2015-06-18 03:16:46 +02001681 if (!val)
Johan Hedbergf2252572015-11-18 12:49:20 +02001682 hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
Florian Grandel847818d2015-06-18 03:16:46 +02001683
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001684 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001685 bool changed = false;
1686
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001687 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001688 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001689 changed = true;
1690 }
1691
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001692 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001693 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001694 changed = true;
1695 }
1696
Johan Hedberg06199cf2012-02-22 16:37:11 +02001697 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1698 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001699 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001700
1701 if (changed)
1702 err = new_settings(hdev, sk);
1703
Johan Hedberg1de028c2012-02-29 19:55:35 -08001704 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001705 }
1706
Johan Hedberg333ae952015-03-17 13:48:47 +02001707 if (pending_find(MGMT_OP_SET_LE, hdev) ||
1708 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001709 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1710 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001711 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001712 }
1713
1714 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1715 if (!cmd) {
1716 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001717 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001718 }
1719
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001720 hci_req_init(&req, hdev);
1721
Johan Hedberg06199cf2012-02-22 16:37:11 +02001722 memset(&hci_cp, 0, sizeof(hci_cp));
1723
1724 if (val) {
1725 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02001726 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001727 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001728 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedbergf2252572015-11-18 12:49:20 +02001729 __hci_req_disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001730 }
1731
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001732 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1733 &hci_cp);
1734
1735 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301736 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001737 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001738
Johan Hedberg1de028c2012-02-29 19:55:35 -08001739unlock:
1740 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001741 return err;
1742}
1743
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001744/* This is a helper function to test for pending mgmt commands that can
1745 * cause CoD or EIR HCI commands. We can only allow one such pending
1746 * mgmt command at a time since otherwise we cannot easily track what
1747 * the current values are, will be, and based on that calculate if a new
1748 * HCI command needs to be sent and if yes with what value.
1749 */
1750static bool pending_eir_or_class(struct hci_dev *hdev)
1751{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001752 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001753
1754 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1755 switch (cmd->opcode) {
1756 case MGMT_OP_ADD_UUID:
1757 case MGMT_OP_REMOVE_UUID:
1758 case MGMT_OP_SET_DEV_CLASS:
1759 case MGMT_OP_SET_POWERED:
1760 return true;
1761 }
1762 }
1763
1764 return false;
1765}
1766
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001767static const u8 bluetooth_base_uuid[] = {
1768 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1769 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1770};
1771
1772static u8 get_uuid_size(const u8 *uuid)
1773{
1774 u32 val;
1775
1776 if (memcmp(uuid, bluetooth_base_uuid, 12))
1777 return 128;
1778
1779 val = get_unaligned_le32(&uuid[12]);
1780 if (val > 0xffff)
1781 return 32;
1782
1783 return 16;
1784}
1785
Johan Hedberg92da6092013-03-15 17:06:55 -05001786static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1787{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001788 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05001789
1790 hci_dev_lock(hdev);
1791
Johan Hedberg333ae952015-03-17 13:48:47 +02001792 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05001793 if (!cmd)
1794 goto unlock;
1795
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001796 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
1797 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05001798
1799 mgmt_pending_remove(cmd);
1800
1801unlock:
1802 hci_dev_unlock(hdev);
1803}
1804
Marcel Holtmann1904a852015-01-11 13:50:44 -08001805static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001806{
1807 BT_DBG("status 0x%02x", status);
1808
1809 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1810}
1811
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001812static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001813{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001814 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001815 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001816 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001817 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001818 int err;
1819
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001821
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001822 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001823
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001824 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001825 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1826 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001827 goto failed;
1828 }
1829
Andre Guedes92c4c202012-06-07 19:05:44 -03001830 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001831 if (!uuid) {
1832 err = -ENOMEM;
1833 goto failed;
1834 }
1835
1836 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001837 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001838 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001839
Johan Hedbergde66aa62013-01-27 00:31:27 +02001840 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001841
Johan Hedberg890ea892013-03-15 17:06:52 -05001842 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001843
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001844 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001845 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001846
Johan Hedberg92da6092013-03-15 17:06:55 -05001847 err = hci_req_run(&req, add_uuid_complete);
1848 if (err < 0) {
1849 if (err != -ENODATA)
1850 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001851
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001852 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1853 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001854 goto failed;
1855 }
1856
1857 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001858 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001859 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001860 goto failed;
1861 }
1862
1863 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001864
1865failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001866 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001867 return err;
1868}
1869
Johan Hedberg24b78d02012-02-23 23:24:30 +02001870static bool enable_service_cache(struct hci_dev *hdev)
1871{
1872 if (!hdev_is_powered(hdev))
1873 return false;
1874
Marcel Holtmann238be782015-03-13 02:11:06 -07001875 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001876 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1877 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001878 return true;
1879 }
1880
1881 return false;
1882}
1883
Marcel Holtmann1904a852015-01-11 13:50:44 -08001884static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001885{
1886 BT_DBG("status 0x%02x", status);
1887
1888 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1889}
1890
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001891static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001892 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001893{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001894 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001895 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001896 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001897 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 -05001898 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001899 int err, found;
1900
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001901 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001903 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001904
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001905 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001906 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1907 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001908 goto unlock;
1909 }
1910
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001911 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02001912 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001913
Johan Hedberg24b78d02012-02-23 23:24:30 +02001914 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001915 err = mgmt_cmd_complete(sk, hdev->id,
1916 MGMT_OP_REMOVE_UUID,
1917 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001918 goto unlock;
1919 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001920
Johan Hedberg9246a862012-02-23 21:33:16 +02001921 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001922 }
1923
1924 found = 0;
1925
Johan Hedberg056341c2013-01-27 00:31:30 +02001926 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001927 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1928 continue;
1929
1930 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001931 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001932 found++;
1933 }
1934
1935 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001936 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1937 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001938 goto unlock;
1939 }
1940
Johan Hedberg9246a862012-02-23 21:33:16 +02001941update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001942 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001943
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02001944 __hci_req_update_class(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02001945 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05001946
Johan Hedberg92da6092013-03-15 17:06:55 -05001947 err = hci_req_run(&req, remove_uuid_complete);
1948 if (err < 0) {
1949 if (err != -ENODATA)
1950 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001951
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001952 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
1953 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001954 goto unlock;
1955 }
1956
1957 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001958 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001959 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001960 goto unlock;
1961 }
1962
1963 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001964
1965unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001966 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001967 return err;
1968}
1969
Marcel Holtmann1904a852015-01-11 13:50:44 -08001970static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05001971{
1972 BT_DBG("status 0x%02x", status);
1973
1974 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1975}
1976
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001977static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001978 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001979{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001980 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001981 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001982 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001983 int err;
1984
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001985 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001986
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001987 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02001988 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1989 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001991 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001992
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001993 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001994 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1995 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001996 goto unlock;
1997 }
1998
1999 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002000 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2001 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002002 goto unlock;
2003 }
2004
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002005 hdev->major_class = cp->major;
2006 hdev->minor_class = cp->minor;
2007
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002008 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002009 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2010 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002011 goto unlock;
2012 }
2013
Johan Hedberg890ea892013-03-15 17:06:52 -05002014 hci_req_init(&req, hdev);
2015
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002016 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002017 hci_dev_unlock(hdev);
2018 cancel_delayed_work_sync(&hdev->service_cache);
2019 hci_dev_lock(hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02002020 __hci_req_update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002021 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002022
Johan Hedberg14bf5ea2015-11-22 19:00:22 +02002023 __hci_req_update_class(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05002024
Johan Hedberg92da6092013-03-15 17:06:55 -05002025 err = hci_req_run(&req, set_class_complete);
2026 if (err < 0) {
2027 if (err != -ENODATA)
2028 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002029
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002030 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2031 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002032 goto unlock;
2033 }
2034
2035 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002036 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002037 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002038 goto unlock;
2039 }
2040
2041 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002042
Johan Hedbergb5235a62012-02-21 14:32:24 +02002043unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002044 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002045 return err;
2046}
2047
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002048static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002049 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002050{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002051 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002052 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2053 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002054 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002055 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002056 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002057
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002058 BT_DBG("request for %s", hdev->name);
2059
2060 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002061 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2062 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002063
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002064 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002065 if (key_count > max_key_count) {
2066 BT_ERR("load_link_keys: too big key_count value %u",
2067 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002068 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2069 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002070 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002071
Johan Hedberg86742e12011-11-07 23:13:38 +02002072 expected_len = sizeof(*cp) + key_count *
2073 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002074 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002075 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002076 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002077 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2078 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002079 }
2080
Johan Hedberg4ae14302013-01-20 14:27:13 +02002081 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002082 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2083 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002085 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002086 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002087
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002088 for (i = 0; i < key_count; i++) {
2089 struct mgmt_link_key_info *key = &cp->keys[i];
2090
Marcel Holtmann8e991132014-01-10 02:07:25 -08002091 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002092 return mgmt_cmd_status(sk, hdev->id,
2093 MGMT_OP_LOAD_LINK_KEYS,
2094 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002095 }
2096
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002097 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002098
2099 hci_link_keys_clear(hdev);
2100
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002101 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002102 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002103 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002104 changed = hci_dev_test_and_clear_flag(hdev,
2105 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002106
2107 if (changed)
2108 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002109
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002110 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002111 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002112
Johan Hedberg58e92932014-06-24 14:00:26 +03002113 /* Always ignore debug keys and require a new pairing if
2114 * the user wants to use them.
2115 */
2116 if (key->type == HCI_LK_DEBUG_COMBINATION)
2117 continue;
2118
Johan Hedberg7652ff62014-06-24 13:15:49 +03002119 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2120 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002121 }
2122
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002123 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002125 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002126
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002127 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002128}
2129
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002130static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002131 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002132{
2133 struct mgmt_ev_device_unpaired ev;
2134
2135 bacpy(&ev.addr.bdaddr, bdaddr);
2136 ev.addr.type = addr_type;
2137
2138 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002139 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002140}
2141
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002142static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002143 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002144{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002145 struct mgmt_cp_unpair_device *cp = data;
2146 struct mgmt_rp_unpair_device rp;
Johan Hedbergfc643612015-10-22 09:38:31 +03002147 struct hci_conn_params *params;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002148 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002149 struct hci_conn *conn;
Johan Hedbergec182f02015-10-21 18:03:03 +03002150 u8 addr_type;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002151 int err;
2152
Johan Hedberga8a1d192011-11-10 15:54:38 +02002153 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002154 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2155 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002156
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002157 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002158 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2159 MGMT_STATUS_INVALID_PARAMS,
2160 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002161
Johan Hedberg118da702013-01-20 14:27:20 +02002162 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002163 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2164 MGMT_STATUS_INVALID_PARAMS,
2165 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002166
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002167 hci_dev_lock(hdev);
2168
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002169 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002170 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2171 MGMT_STATUS_NOT_POWERED, &rp,
2172 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002173 goto unlock;
2174 }
2175
Johan Hedberge0b2b272014-02-18 17:14:31 +02002176 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002177 /* If disconnection is requested, then look up the
2178 * connection. If the remote device is connected, it
2179 * will be later used to terminate the link.
2180 *
2181 * Setting it to NULL explicitly will cause no
2182 * termination of the link.
2183 */
2184 if (cp->disconnect)
2185 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2186 &cp->addr.bdaddr);
2187 else
2188 conn = NULL;
2189
Johan Hedberg124f6e32012-02-09 13:50:12 +02002190 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedbergec182f02015-10-21 18:03:03 +03002191 if (err < 0) {
2192 err = mgmt_cmd_complete(sk, hdev->id,
2193 MGMT_OP_UNPAIR_DEVICE,
2194 MGMT_STATUS_NOT_PAIRED, &rp,
2195 sizeof(rp));
2196 goto unlock;
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002197 }
2198
Johan Hedbergec182f02015-10-21 18:03:03 +03002199 goto done;
Johan Hedberge0b2b272014-02-18 17:14:31 +02002200 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002201
Johan Hedbergec182f02015-10-21 18:03:03 +03002202 /* LE address type */
2203 addr_type = le_addr_type(cp->addr.type);
2204
2205 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2206
2207 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002208 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002209 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2210 MGMT_STATUS_NOT_PAIRED, &rp,
2211 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002212 goto unlock;
2213 }
2214
Johan Hedbergec182f02015-10-21 18:03:03 +03002215 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, addr_type);
2216 if (!conn) {
2217 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2218 goto done;
2219 }
2220
Johan Hedbergc81d5552015-10-22 09:38:35 +03002221 /* Abort any ongoing SMP pairing */
2222 smp_cancel_pairing(conn);
2223
Johan Hedbergec182f02015-10-21 18:03:03 +03002224 /* Defer clearing up the connection parameters until closing to
2225 * give a chance of keeping them if a repairing happens.
2226 */
2227 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2228
Johan Hedbergfc643612015-10-22 09:38:31 +03002229 /* Disable auto-connection parameters if present */
2230 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
2231 if (params) {
2232 if (params->explicit_connect)
2233 params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
2234 else
2235 params->auto_connect = HCI_AUTO_CONN_DISABLED;
2236 }
2237
Johan Hedbergec182f02015-10-21 18:03:03 +03002238 /* If disconnection is not requested, then clear the connection
2239 * variable so that the link is not terminated.
2240 */
2241 if (!cp->disconnect)
2242 conn = NULL;
2243
2244done:
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002245 /* If the connection variable is set, then termination of the
2246 * link is requested.
2247 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002248 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002249 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2250 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002251 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002252 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253 }
2254
Johan Hedberg124f6e32012-02-09 13:50:12 +02002255 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002256 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002257 if (!cmd) {
2258 err = -ENOMEM;
2259 goto unlock;
2260 }
2261
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002262 cmd->cmd_complete = addr_cmd_complete;
2263
Johan Hedberg89e0ccc2015-10-22 10:49:38 +03002264 err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002265 if (err < 0)
2266 mgmt_pending_remove(cmd);
2267
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002268unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002270 return err;
2271}
2272
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002273static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002275{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002276 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002277 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002278 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002279 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002280 int err;
2281
2282 BT_DBG("");
2283
Johan Hedberg06a63b12013-01-20 14:27:21 +02002284 memset(&rp, 0, sizeof(rp));
2285 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2286 rp.addr.type = cp->addr.type;
2287
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002288 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002289 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2290 MGMT_STATUS_INVALID_PARAMS,
2291 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002292
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002294
2295 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002296 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2297 MGMT_STATUS_NOT_POWERED, &rp,
2298 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002299 goto failed;
2300 }
2301
Johan Hedberg333ae952015-03-17 13:48:47 +02002302 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002303 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2304 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002305 goto failed;
2306 }
2307
Andre Guedes591f47f2012-04-24 21:02:49 -03002308 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002309 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2310 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002311 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002312 conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
2313 le_addr_type(cp->addr.type));
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002314
Vishal Agarwalf9607272012-06-13 05:32:43 +05302315 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002316 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2317 MGMT_STATUS_NOT_CONNECTED, &rp,
2318 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002319 goto failed;
2320 }
2321
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002322 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002323 if (!cmd) {
2324 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002325 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002326 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002327
Johan Hedbergf5818c22014-12-05 13:36:02 +02002328 cmd->cmd_complete = generic_cmd_complete;
2329
Johan Hedberge3f2f922014-08-18 20:33:33 +03002330 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002331 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002332 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002333
2334failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002335 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002336 return err;
2337}
2338
Andre Guedes57c14772012-04-24 21:02:50 -03002339static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002340{
2341 switch (link_type) {
2342 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002343 switch (addr_type) {
2344 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002345 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002346
Johan Hedberg48264f02011-11-09 13:58:58 +02002347 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002348 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002349 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002350 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002351
Johan Hedberg4c659c32011-11-07 23:13:39 +02002352 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002353 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002354 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002355 }
2356}
2357
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002358static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2359 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002360{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002361 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002362 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002363 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002364 int err;
2365 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002366
2367 BT_DBG("");
2368
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002370
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002371 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002372 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2373 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002374 goto unlock;
2375 }
2376
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002377 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002378 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2379 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002380 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002381 }
2382
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002383 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002384 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002385 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002386 err = -ENOMEM;
2387 goto unlock;
2388 }
2389
Johan Hedberg2784eb42011-01-21 13:56:35 +02002390 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002391 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002392 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2393 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002394 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002395 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002396 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002397 continue;
2398 i++;
2399 }
2400
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002401 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002402
Johan Hedberg4c659c32011-11-07 23:13:39 +02002403 /* Recalculate length in case of filtered SCO connections, etc */
2404 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002405
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002406 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2407 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002408
Johan Hedberga38528f2011-01-22 06:46:43 +02002409 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002410
2411unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002412 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002413 return err;
2414}
2415
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002416static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002417 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002418{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002419 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002420 int err;
2421
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002422 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002423 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002424 if (!cmd)
2425 return -ENOMEM;
2426
Johan Hedbergd8457692012-02-17 14:24:57 +02002427 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002428 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002429 if (err < 0)
2430 mgmt_pending_remove(cmd);
2431
2432 return err;
2433}
2434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002435static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002436 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002437{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002438 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002439 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002440 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002441 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002442 int err;
2443
2444 BT_DBG("");
2445
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002446 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002447
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002448 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002449 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2450 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002451 goto failed;
2452 }
2453
Johan Hedbergd8457692012-02-17 14:24:57 +02002454 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002455 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002456 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2457 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002458 goto failed;
2459 }
2460
2461 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002462 struct mgmt_cp_pin_code_neg_reply ncp;
2463
2464 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002465
2466 BT_ERR("PIN code is not 16 bytes long");
2467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002468 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002469 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002470 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2471 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002472
2473 goto failed;
2474 }
2475
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002476 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002477 if (!cmd) {
2478 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002479 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002480 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002481
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002482 cmd->cmd_complete = addr_cmd_complete;
2483
Johan Hedbergd8457692012-02-17 14:24:57 +02002484 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002486 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002487
2488 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2489 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002490 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002491
2492failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002493 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002494 return err;
2495}
2496
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2498 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002499{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002500 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002501
2502 BT_DBG("");
2503
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002504 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002505 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
2506 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002507
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002508 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002509
2510 hdev->io_capability = cp->io_capability;
2511
2512 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002513 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002515 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002516
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002517 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
2518 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002519}
2520
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002521static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002522{
2523 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002524 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002525
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002526 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002527 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2528 continue;
2529
Johan Hedberge9a416b2011-02-19 12:05:56 -03002530 if (cmd->user_data != conn)
2531 continue;
2532
2533 return cmd;
2534 }
2535
2536 return NULL;
2537}
2538
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002539static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002540{
2541 struct mgmt_rp_pair_device rp;
2542 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02002543 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002544
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02002545 bacpy(&rp.addr.bdaddr, &conn->dst);
2546 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002547
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002548 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
2549 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002550
2551 /* So we don't get further callbacks for this connection */
2552 conn->connect_cfm_cb = NULL;
2553 conn->security_cfm_cb = NULL;
2554 conn->disconn_cfm_cb = NULL;
2555
David Herrmann76a68ba2013-04-06 20:28:37 +02002556 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002557
2558 /* The device is paired so there is no need to remove
2559 * its connection parameters anymore.
2560 */
2561 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02002562
2563 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02002564
2565 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002566}
2567
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002568void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2569{
2570 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002571 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002572
2573 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002574 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02002575 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02002576 mgmt_pending_remove(cmd);
2577 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002578}
2579
Johan Hedberge9a416b2011-02-19 12:05:56 -03002580static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2581{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002582 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002583
2584 BT_DBG("status %u", status);
2585
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002586 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002587 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002588 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002589 return;
2590 }
2591
2592 cmd->cmd_complete(cmd, mgmt_status(status));
2593 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002594}
2595
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002596static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302597{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002598 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302599
2600 BT_DBG("status %u", status);
2601
2602 if (!status)
2603 return;
2604
2605 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02002606 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302607 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02002608 return;
2609 }
2610
2611 cmd->cmd_complete(cmd, mgmt_status(status));
2612 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302613}
2614
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002615static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002616 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002617{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002618 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002619 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002620 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002621 u8 sec_level, auth_type;
2622 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002623 int err;
2624
2625 BT_DBG("");
2626
Szymon Jancf950a30e2013-01-18 12:48:07 +01002627 memset(&rp, 0, sizeof(rp));
2628 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2629 rp.addr.type = cp->addr.type;
2630
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002631 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002632 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2633 MGMT_STATUS_INVALID_PARAMS,
2634 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002635
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002636 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002637 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2638 MGMT_STATUS_INVALID_PARAMS,
2639 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03002640
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002641 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002643 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002644 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2645 MGMT_STATUS_NOT_POWERED, &rp,
2646 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002647 goto unlock;
2648 }
2649
Johan Hedberg55e76b32015-03-10 22:34:40 +02002650 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
2651 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2652 MGMT_STATUS_ALREADY_PAIRED, &rp,
2653 sizeof(rp));
2654 goto unlock;
2655 }
2656
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002657 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02002658 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002659
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002660 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002661 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2662 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002663 } else {
Johan Hedberg85813a72015-10-21 18:02:59 +03002664 u8 addr_type = le_addr_type(cp->addr.type);
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002665 struct hci_conn_params *p;
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002666
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002667 /* When pairing a new device, it is expected to remember
2668 * this device for future connections. Adding the connection
2669 * parameter information ahead of time allows tracking
2670 * of the slave preferred values and will speed up any
2671 * further connection establishment.
2672 *
2673 * If connection parameters already exist, then they
2674 * will be kept and this function does nothing.
2675 */
Jakub Pawlowski5157b8a2015-10-16 10:07:54 +03002676 p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
2677
2678 if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
2679 p->auto_connect = HCI_AUTO_CONN_DISABLED;
Marcel Holtmann7c264b12014-06-30 12:34:40 +02002680
Jakub Pawlowskifa142222015-08-07 20:22:56 +02002681 conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
2682 addr_type, sec_level,
Johan Hedberg0ad06aa2015-11-11 14:44:57 +02002683 HCI_LE_CONN_TIMEOUT);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002684 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002685
Ville Tervo30e76272011-02-22 16:10:53 -03002686 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002687 int status;
2688
2689 if (PTR_ERR(conn) == -EBUSY)
2690 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01002691 else if (PTR_ERR(conn) == -EOPNOTSUPP)
2692 status = MGMT_STATUS_NOT_SUPPORTED;
2693 else if (PTR_ERR(conn) == -ECONNREFUSED)
2694 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002695 else
2696 status = MGMT_STATUS_CONNECT_FAILED;
2697
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002698 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2699 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002700 goto unlock;
2701 }
2702
2703 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002704 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002705 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2706 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002707 goto unlock;
2708 }
2709
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002710 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002711 if (!cmd) {
2712 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002713 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002714 goto unlock;
2715 }
2716
Johan Hedberg04ab2742014-12-05 13:36:04 +02002717 cmd->cmd_complete = pairing_complete;
2718
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002719 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002720 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002721 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002722 conn->security_cfm_cb = pairing_complete_cb;
2723 conn->disconn_cfm_cb = pairing_complete_cb;
2724 } else {
2725 conn->connect_cfm_cb = le_pairing_complete_cb;
2726 conn->security_cfm_cb = le_pairing_complete_cb;
2727 conn->disconn_cfm_cb = le_pairing_complete_cb;
2728 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002729
Johan Hedberge9a416b2011-02-19 12:05:56 -03002730 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03002731 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732
Johan Hedberg6f78fd42014-07-30 08:35:48 +03002733 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02002734 hci_conn_security(conn, sec_level, auth_type, true)) {
2735 cmd->cmd_complete(cmd, 0);
2736 mgmt_pending_remove(cmd);
2737 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03002738
2739 err = 0;
2740
2741unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002742 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002743 return err;
2744}
2745
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002746static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2747 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002748{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002749 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002750 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02002751 struct hci_conn *conn;
2752 int err;
2753
2754 BT_DBG("");
2755
Johan Hedberg28424702012-02-02 04:02:29 +02002756 hci_dev_lock(hdev);
2757
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002758 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002759 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2760 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002761 goto unlock;
2762 }
2763
Johan Hedberg333ae952015-03-17 13:48:47 +02002764 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002765 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002766 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2767 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002768 goto unlock;
2769 }
2770
2771 conn = cmd->user_data;
2772
2773 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002774 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2775 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002776 goto unlock;
2777 }
2778
Johan Hedberga511b352014-12-11 21:45:45 +02002779 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
2780 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02002781
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002782 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2783 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002784unlock:
2785 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002786 return err;
2787}
2788
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002789static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002790 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002791 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002792{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002793 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002794 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002795 int err;
2796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002797 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002798
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002799 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002800 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2801 MGMT_STATUS_NOT_POWERED, addr,
2802 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002803 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002804 }
2805
Johan Hedberg1707c602013-03-15 17:07:15 -05002806 if (addr->type == BDADDR_BREDR)
2807 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002808 else
Johan Hedberg9d4c1cc2015-10-21 18:03:01 +03002809 conn = hci_conn_hash_lookup_le(hdev, &addr->bdaddr,
2810 le_addr_type(addr->type));
Brian Gix47c15e22011-11-16 13:53:14 -08002811
Johan Hedberg272d90d2012-02-09 15:26:12 +02002812 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002813 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2814 MGMT_STATUS_NOT_CONNECTED, addr,
2815 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002816 goto done;
2817 }
2818
Johan Hedberg1707c602013-03-15 17:07:15 -05002819 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08002820 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08002821 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002822 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2823 MGMT_STATUS_SUCCESS, addr,
2824 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002825 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002826 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
2827 MGMT_STATUS_FAILED, addr,
2828 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002829
Brian Gix47c15e22011-11-16 13:53:14 -08002830 goto done;
2831 }
2832
Johan Hedberg1707c602013-03-15 17:07:15 -05002833 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002834 if (!cmd) {
2835 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002836 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002837 }
2838
Johan Hedberg7776d1d2014-12-05 13:36:03 +02002839 cmd->cmd_complete = addr_cmd_complete;
2840
Brian Gix0df4c182011-11-16 13:53:13 -08002841 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002842 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2843 struct hci_cp_user_passkey_reply cp;
2844
Johan Hedberg1707c602013-03-15 17:07:15 -05002845 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002846 cp.passkey = passkey;
2847 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2848 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002849 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2850 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002851
Johan Hedberga664b5b2011-02-19 12:06:02 -03002852 if (err < 0)
2853 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002854
Brian Gix0df4c182011-11-16 13:53:13 -08002855done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002856 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002857 return err;
2858}
2859
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302860static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2861 void *data, u16 len)
2862{
2863 struct mgmt_cp_pin_code_neg_reply *cp = data;
2864
2865 BT_DBG("");
2866
Johan Hedberg1707c602013-03-15 17:07:15 -05002867 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302868 MGMT_OP_PIN_CODE_NEG_REPLY,
2869 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2870}
2871
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002872static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2873 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002874{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002875 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002876
2877 BT_DBG("");
2878
2879 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02002880 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
2881 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002882
Johan Hedberg1707c602013-03-15 17:07:15 -05002883 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002884 MGMT_OP_USER_CONFIRM_REPLY,
2885 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002886}
2887
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002888static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002889 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002890{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002891 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002892
2893 BT_DBG("");
2894
Johan Hedberg1707c602013-03-15 17:07:15 -05002895 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002896 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2897 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002898}
2899
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002900static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2901 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002902{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002903 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002904
2905 BT_DBG("");
2906
Johan Hedberg1707c602013-03-15 17:07:15 -05002907 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002908 MGMT_OP_USER_PASSKEY_REPLY,
2909 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002910}
2911
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002912static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002913 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002914{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002915 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002916
2917 BT_DBG("");
2918
Johan Hedberg1707c602013-03-15 17:07:15 -05002919 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002920 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2921 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002922}
2923
Marcel Holtmann1904a852015-01-11 13:50:44 -08002924static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05002925{
2926 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002927 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05002928
2929 BT_DBG("status 0x%02x", status);
2930
2931 hci_dev_lock(hdev);
2932
Johan Hedberg333ae952015-03-17 13:48:47 +02002933 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05002934 if (!cmd)
2935 goto unlock;
2936
2937 cp = cmd->param;
2938
2939 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002940 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2941 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05002942 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002943 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2944 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05002945
2946 mgmt_pending_remove(cmd);
2947
2948unlock:
2949 hci_dev_unlock(hdev);
2950}
2951
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002952static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002953 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002954{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002955 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002956 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002957 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002958 int err;
2959
2960 BT_DBG("");
2961
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002962 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002963
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002964 /* If the old values are the same as the new ones just return a
2965 * direct command complete event.
2966 */
2967 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2968 !memcmp(hdev->short_name, cp->short_name,
2969 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002970 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2971 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002972 goto failed;
2973 }
2974
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002975 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002976
Johan Hedbergb5235a62012-02-21 14:32:24 +02002977 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002978 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002979
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002980 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2981 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002982 if (err < 0)
2983 goto failed;
2984
Marcel Holtmannf6b77122015-03-14 19:28:05 -07002985 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
2986 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002987
Johan Hedbergb5235a62012-02-21 14:32:24 +02002988 goto failed;
2989 }
2990
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002991 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002992 if (!cmd) {
2993 err = -ENOMEM;
2994 goto failed;
2995 }
2996
Johan Hedberg13928972013-03-15 17:07:00 -05002997 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2998
Johan Hedberg890ea892013-03-15 17:06:52 -05002999 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003000
3001 if (lmp_bredr_capable(hdev)) {
Johan Hedberg00cf5042015-11-25 16:15:41 +02003002 __hci_req_update_name(&req);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003003 __hci_req_update_eir(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003004 }
3005
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003006 /* The name is stored in the scan response data and so
3007 * no need to udpate the advertising data here.
3008 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003009 if (lmp_le_capable(hdev))
Johan Hedbergcab054a2015-11-30 11:21:45 +02003010 __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
Johan Hedberg3f985052013-03-15 17:07:02 -05003011
Johan Hedberg13928972013-03-15 17:07:00 -05003012 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003013 if (err < 0)
3014 mgmt_pending_remove(cmd);
3015
3016failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003017 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003018 return err;
3019}
3020
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003021static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3022 u16 opcode, struct sk_buff *skb)
3023{
3024 struct mgmt_rp_read_local_oob_data mgmt_rp;
3025 size_t rp_size = sizeof(mgmt_rp);
3026 struct mgmt_pending_cmd *cmd;
3027
3028 BT_DBG("%s status %u", hdev->name, status);
3029
3030 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
3031 if (!cmd)
3032 return;
3033
3034 if (status || !skb) {
3035 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3036 status ? mgmt_status(status) : MGMT_STATUS_FAILED);
3037 goto remove;
3038 }
3039
3040 memset(&mgmt_rp, 0, sizeof(mgmt_rp));
3041
3042 if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
3043 struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
3044
3045 if (skb->len < sizeof(*rp)) {
3046 mgmt_cmd_status(cmd->sk, hdev->id,
3047 MGMT_OP_READ_LOCAL_OOB_DATA,
3048 MGMT_STATUS_FAILED);
3049 goto remove;
3050 }
3051
3052 memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash));
3053 memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand));
3054
3055 rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256);
3056 } else {
3057 struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
3058
3059 if (skb->len < sizeof(*rp)) {
3060 mgmt_cmd_status(cmd->sk, hdev->id,
3061 MGMT_OP_READ_LOCAL_OOB_DATA,
3062 MGMT_STATUS_FAILED);
3063 goto remove;
3064 }
3065
3066 memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192));
3067 memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192));
3068
3069 memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256));
3070 memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256));
3071 }
3072
3073 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3074 MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
3075
3076remove:
3077 mgmt_pending_remove(cmd);
3078}
3079
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003080static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003081 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003082{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003083 struct mgmt_pending_cmd *cmd;
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003084 struct hci_request req;
Szymon Jancc35938b2011-03-22 13:12:21 +01003085 int err;
3086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003087 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003089 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003090
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003091 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003092 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3093 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003094 goto unlock;
3095 }
3096
Andre Guedes9a1a1992012-07-24 15:03:48 -03003097 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003098 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3099 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003100 goto unlock;
3101 }
3102
Johan Hedberg333ae952015-03-17 13:48:47 +02003103 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003104 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3105 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003106 goto unlock;
3107 }
3108
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003109 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003110 if (!cmd) {
3111 err = -ENOMEM;
3112 goto unlock;
3113 }
3114
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003115 hci_req_init(&req, hdev);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003116
Johan Hedberg1b9441f2015-04-02 13:41:13 +03003117 if (bredr_sc_enabled(hdev))
3118 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
3119 else
3120 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3121
3122 err = hci_req_run_skb(&req, read_local_oob_data_complete);
Szymon Jancc35938b2011-03-22 13:12:21 +01003123 if (err < 0)
3124 mgmt_pending_remove(cmd);
3125
3126unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003127 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003128 return err;
3129}
3130
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003131static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003133{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003134 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003135 int err;
3136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003137 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003138
Johan Hedberg5d57e792015-01-23 10:10:38 +02003139 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003140 return mgmt_cmd_complete(sk, hdev->id,
3141 MGMT_OP_ADD_REMOTE_OOB_DATA,
3142 MGMT_STATUS_INVALID_PARAMS,
3143 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003144
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003145 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003146
Marcel Holtmannec109112014-01-10 02:07:30 -08003147 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3148 struct mgmt_cp_add_remote_oob_data *cp = data;
3149 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003150
Johan Hedbergc19a4952014-11-17 20:52:19 +02003151 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003152 err = mgmt_cmd_complete(sk, hdev->id,
3153 MGMT_OP_ADD_REMOTE_OOB_DATA,
3154 MGMT_STATUS_INVALID_PARAMS,
3155 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003156 goto unlock;
3157 }
3158
Marcel Holtmannec109112014-01-10 02:07:30 -08003159 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003160 cp->addr.type, cp->hash,
3161 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003162 if (err < 0)
3163 status = MGMT_STATUS_FAILED;
3164 else
3165 status = MGMT_STATUS_SUCCESS;
3166
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003167 err = mgmt_cmd_complete(sk, hdev->id,
3168 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3169 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003170 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3171 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003172 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003173 u8 status;
3174
Johan Hedberg86df9202014-10-26 20:52:27 +01003175 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003176 /* Enforce zero-valued 192-bit parameters as
3177 * long as legacy SMP OOB isn't implemented.
3178 */
3179 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3180 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003181 err = mgmt_cmd_complete(sk, hdev->id,
3182 MGMT_OP_ADD_REMOTE_OOB_DATA,
3183 MGMT_STATUS_INVALID_PARAMS,
3184 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003185 goto unlock;
3186 }
3187
Johan Hedberg86df9202014-10-26 20:52:27 +01003188 rand192 = NULL;
3189 hash192 = NULL;
3190 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003191 /* In case one of the P-192 values is set to zero,
3192 * then just disable OOB data for P-192.
3193 */
3194 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3195 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3196 rand192 = NULL;
3197 hash192 = NULL;
3198 } else {
3199 rand192 = cp->rand192;
3200 hash192 = cp->hash192;
3201 }
3202 }
3203
3204 /* In case one of the P-256 values is set to zero, then just
3205 * disable OOB data for P-256.
3206 */
3207 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3208 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3209 rand256 = NULL;
3210 hash256 = NULL;
3211 } else {
3212 rand256 = cp->rand256;
3213 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003214 }
3215
Johan Hedberg81328d52014-10-26 20:33:47 +01003216 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003217 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003218 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003219 if (err < 0)
3220 status = MGMT_STATUS_FAILED;
3221 else
3222 status = MGMT_STATUS_SUCCESS;
3223
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003224 err = mgmt_cmd_complete(sk, hdev->id,
3225 MGMT_OP_ADD_REMOTE_OOB_DATA,
3226 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003227 } else {
3228 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003229 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3230 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003231 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003232
Johan Hedbergc19a4952014-11-17 20:52:19 +02003233unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003234 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003235 return err;
3236}
3237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003238static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003239 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003240{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003241 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003242 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003243 int err;
3244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003245 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003246
Johan Hedbergc19a4952014-11-17 20:52:19 +02003247 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003248 return mgmt_cmd_complete(sk, hdev->id,
3249 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3250 MGMT_STATUS_INVALID_PARAMS,
3251 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003252
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003253 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003254
Johan Hedbergeedbd582014-11-15 09:34:23 +02003255 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3256 hci_remote_oob_data_clear(hdev);
3257 status = MGMT_STATUS_SUCCESS;
3258 goto done;
3259 }
3260
Johan Hedberg6928a922014-10-26 20:46:09 +01003261 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003262 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003263 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003264 else
Szymon Janca6785be2012-12-13 15:11:21 +01003265 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003266
Johan Hedbergeedbd582014-11-15 09:34:23 +02003267done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003268 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3269 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003271 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003272 return err;
3273}
3274
Johan Hedberge68f0722015-11-11 08:30:30 +02003275void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes7c307722013-04-30 15:29:28 -03003276{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003277 struct mgmt_pending_cmd *cmd;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003278
Andre Guedes7c307722013-04-30 15:29:28 -03003279 BT_DBG("status %d", status);
3280
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003281 hci_dev_lock(hdev);
3282
Johan Hedberg333ae952015-03-17 13:48:47 +02003283 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003284 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003285 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003286
Johan Hedberg78b781c2016-01-05 13:19:32 +02003287 if (!cmd)
3288 cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev);
3289
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003290 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003291 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003292 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003293 }
3294
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003295 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003296}
3297
Johan Hedberg591752a2015-11-11 08:11:24 +02003298static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
3299 uint8_t *mgmt_status)
3300{
3301 switch (type) {
3302 case DISCOV_TYPE_LE:
3303 *mgmt_status = mgmt_le_support(hdev);
3304 if (*mgmt_status)
3305 return false;
3306 break;
3307 case DISCOV_TYPE_INTERLEAVED:
3308 *mgmt_status = mgmt_le_support(hdev);
3309 if (*mgmt_status)
3310 return false;
3311 /* Intentional fall-through */
3312 case DISCOV_TYPE_BREDR:
3313 *mgmt_status = mgmt_bredr_support(hdev);
3314 if (*mgmt_status)
3315 return false;
3316 break;
3317 default:
3318 *mgmt_status = MGMT_STATUS_INVALID_PARAMS;
3319 return false;
3320 }
3321
3322 return true;
3323}
3324
Johan Hedberg78b781c2016-01-05 13:19:32 +02003325static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
3326 u16 op, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003327{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003328 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003329 struct mgmt_pending_cmd *cmd;
Marcel Holtmann80190442014-12-04 11:36:36 +01003330 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003331 int err;
3332
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003333 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003334
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003335 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003336
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003337 if (!hdev_is_powered(hdev)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003338 err = mgmt_cmd_complete(sk, hdev->id, op,
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003339 MGMT_STATUS_NOT_POWERED,
3340 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003341 goto failed;
3342 }
3343
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003344 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003345 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003346 err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,
3347 &cp->type, sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003348 goto failed;
3349 }
3350
Johan Hedberg591752a2015-11-11 08:11:24 +02003351 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
Johan Hedberg78b781c2016-01-05 13:19:32 +02003352 err = mgmt_cmd_complete(sk, hdev->id, op, status,
3353 &cp->type, sizeof(cp->type));
Johan Hedberg591752a2015-11-11 08:11:24 +02003354 goto failed;
3355 }
3356
Marcel Holtmann22078802014-12-05 11:45:22 +01003357 /* Clear the discovery filter first to free any previously
3358 * allocated memory for the UUID list.
3359 */
3360 hci_discovery_filter_clear(hdev);
3361
Andre Guedes4aab14e2012-02-17 20:39:36 -03003362 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003363 hdev->discovery.report_invalid_rssi = false;
Johan Hedberg78b781c2016-01-05 13:19:32 +02003364 if (op == MGMT_OP_START_LIMITED_DISCOVERY)
3365 hdev->discovery.limited = true;
3366 else
3367 hdev->discovery.limited = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003368
Johan Hedberg78b781c2016-01-05 13:19:32 +02003369 cmd = mgmt_pending_add(sk, op, hdev, data, len);
Johan Hedberge68f0722015-11-11 08:30:30 +02003370 if (!cmd) {
3371 err = -ENOMEM;
Johan Hedberg04106752013-01-10 14:54:09 +02003372 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003373 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003374
Johan Hedberge68f0722015-11-11 08:30:30 +02003375 cmd->cmd_complete = generic_cmd_complete;
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003376
3377 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003378 queue_work(hdev->req_workqueue, &hdev->discov_update);
3379 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003380
3381failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003382 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003383 return err;
3384}
3385
Johan Hedberg78b781c2016-01-05 13:19:32 +02003386static int start_discovery(struct sock *sk, struct hci_dev *hdev,
3387 void *data, u16 len)
3388{
3389 return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,
3390 data, len);
3391}
3392
3393static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
3394 void *data, u16 len)
3395{
3396 return start_discovery_internal(sk, hdev,
3397 MGMT_OP_START_LIMITED_DISCOVERY,
3398 data, len);
3399}
3400
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003401static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
3402 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03003403{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003404 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
3405 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02003406}
3407
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003408static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
3409 void *data, u16 len)
3410{
3411 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003412 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003413 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
3414 u16 uuid_count, expected_len;
3415 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03003416 int err;
3417
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003418 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003419
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003420 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003421
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003422 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003423 err = mgmt_cmd_complete(sk, hdev->id,
3424 MGMT_OP_START_SERVICE_DISCOVERY,
3425 MGMT_STATUS_NOT_POWERED,
3426 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003427 goto failed;
3428 }
3429
3430 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003431 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003432 err = mgmt_cmd_complete(sk, hdev->id,
3433 MGMT_OP_START_SERVICE_DISCOVERY,
3434 MGMT_STATUS_BUSY, &cp->type,
3435 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003436 goto failed;
3437 }
3438
3439 uuid_count = __le16_to_cpu(cp->uuid_count);
3440 if (uuid_count > max_uuid_count) {
3441 BT_ERR("service_discovery: too big uuid_count value %u",
3442 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003443 err = mgmt_cmd_complete(sk, hdev->id,
3444 MGMT_OP_START_SERVICE_DISCOVERY,
3445 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3446 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003447 goto failed;
3448 }
3449
3450 expected_len = sizeof(*cp) + uuid_count * 16;
3451 if (expected_len != len) {
3452 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
3453 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003454 err = mgmt_cmd_complete(sk, hdev->id,
3455 MGMT_OP_START_SERVICE_DISCOVERY,
3456 MGMT_STATUS_INVALID_PARAMS, &cp->type,
3457 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003458 goto failed;
3459 }
3460
Johan Hedberg591752a2015-11-11 08:11:24 +02003461 if (!discovery_type_is_valid(hdev, cp->type, &status)) {
3462 err = mgmt_cmd_complete(sk, hdev->id,
3463 MGMT_OP_START_SERVICE_DISCOVERY,
3464 status, &cp->type, sizeof(cp->type));
3465 goto failed;
3466 }
3467
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003468 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02003469 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003470 if (!cmd) {
3471 err = -ENOMEM;
3472 goto failed;
3473 }
3474
Johan Hedberg2922a942014-12-05 13:36:06 +02003475 cmd->cmd_complete = service_discovery_cmd_complete;
3476
Marcel Holtmann22078802014-12-05 11:45:22 +01003477 /* Clear the discovery filter first to free any previously
3478 * allocated memory for the UUID list.
3479 */
3480 hci_discovery_filter_clear(hdev);
3481
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003482 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003483 hdev->discovery.type = cp->type;
3484 hdev->discovery.rssi = cp->rssi;
3485 hdev->discovery.uuid_count = uuid_count;
3486
3487 if (uuid_count > 0) {
3488 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
3489 GFP_KERNEL);
3490 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003491 err = mgmt_cmd_complete(sk, hdev->id,
3492 MGMT_OP_START_SERVICE_DISCOVERY,
3493 MGMT_STATUS_FAILED,
3494 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003495 mgmt_pending_remove(cmd);
3496 goto failed;
3497 }
3498 }
3499
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003500 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberge68f0722015-11-11 08:30:30 +02003501 queue_work(hdev->req_workqueue, &hdev->discov_update);
3502 err = 0;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003503
3504failed:
3505 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03003506 return err;
3507}
3508
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003509void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
Andre Guedes0e05bba2013-04-30 15:29:33 -03003510{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003511 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003512
Andre Guedes0e05bba2013-04-30 15:29:33 -03003513 BT_DBG("status %d", status);
3514
3515 hci_dev_lock(hdev);
3516
Johan Hedberg333ae952015-03-17 13:48:47 +02003517 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003518 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003519 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003520 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003521 }
3522
Andre Guedes0e05bba2013-04-30 15:29:33 -03003523 hci_dev_unlock(hdev);
3524}
3525
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003526static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003527 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003528{
Johan Hedbergd9306502012-02-20 23:25:18 +02003529 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003530 struct mgmt_pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04003531 int err;
3532
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003533 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003534
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003535 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003536
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003537 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003538 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3539 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3540 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003541 goto unlock;
3542 }
3543
3544 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003545 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3546 MGMT_STATUS_INVALID_PARAMS,
3547 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003548 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003549 }
3550
Johan Hedberg2922a942014-12-05 13:36:06 +02003551 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003552 if (!cmd) {
3553 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003554 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003555 }
3556
Johan Hedberg2922a942014-12-05 13:36:06 +02003557 cmd->cmd_complete = generic_cmd_complete;
3558
Johan Hedberg2154d3f2015-11-11 08:30:45 +02003559 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
3560 queue_work(hdev->req_workqueue, &hdev->discov_update);
3561 err = 0;
Johan Hedberg14a53662011-04-27 10:29:56 -04003562
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003563unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003564 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003565 return err;
3566}
3567
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003568static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003569 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003570{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003571 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003572 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003573 int err;
3574
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003575 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003576
Johan Hedberg561aafb2012-01-04 13:31:59 +02003577 hci_dev_lock(hdev);
3578
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003579 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003580 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3581 MGMT_STATUS_FAILED, &cp->addr,
3582 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003583 goto failed;
3584 }
3585
Johan Hedberga198e7b2012-02-17 14:27:06 +02003586 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003587 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003588 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
3589 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
3590 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003591 goto failed;
3592 }
3593
3594 if (cp->name_known) {
3595 e->name_state = NAME_KNOWN;
3596 list_del(&e->list);
3597 } else {
3598 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003599 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003600 }
3601
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003602 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
3603 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003604
3605failed:
3606 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003607 return err;
3608}
3609
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003610static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003611 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003612{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003613 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003614 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003615 int err;
3616
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003617 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003618
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003619 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003620 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3621 MGMT_STATUS_INVALID_PARAMS,
3622 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003623
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003624 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003625
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003626 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
3627 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003628 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003629 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003630 goto done;
3631 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003632
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003633 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3634 sk);
3635 status = MGMT_STATUS_SUCCESS;
3636
3637done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003638 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
3639 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003640
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003641 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003642
3643 return err;
3644}
3645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003646static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003647 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003648{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003649 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003650 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003651 int err;
3652
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003653 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003654
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003655 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003656 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3657 MGMT_STATUS_INVALID_PARAMS,
3658 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003660 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003661
Johan Hedbergdcc36c12014-07-09 12:59:13 +03003662 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
3663 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003664 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003665 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003666 goto done;
3667 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003668
Johan Hedberg2a8357f2014-07-01 22:09:47 +03003669 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
3670 sk);
3671 status = MGMT_STATUS_SUCCESS;
3672
3673done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003674 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
3675 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003676
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003677 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003678
3679 return err;
3680}
3681
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003682static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3683 u16 len)
3684{
3685 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003686 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003687 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003688 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003689
3690 BT_DBG("%s", hdev->name);
3691
Szymon Jancc72d4b82012-03-16 16:02:57 +01003692 source = __le16_to_cpu(cp->source);
3693
3694 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02003695 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3696 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01003697
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003698 hci_dev_lock(hdev);
3699
Szymon Jancc72d4b82012-03-16 16:02:57 +01003700 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003701 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3702 hdev->devid_product = __le16_to_cpu(cp->product);
3703 hdev->devid_version = __le16_to_cpu(cp->version);
3704
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003705 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
3706 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003707
Johan Hedberg890ea892013-03-15 17:06:52 -05003708 hci_req_init(&req, hdev);
Johan Hedbergb1a89172015-11-25 16:15:42 +02003709 __hci_req_update_eir(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003710 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003711
3712 hci_dev_unlock(hdev);
3713
3714 return err;
3715}
3716
Arman Uguray24b4f382015-03-23 15:57:12 -07003717static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
3718 u16 opcode)
3719{
3720 BT_DBG("status %d", status);
3721}
3722
Marcel Holtmann1904a852015-01-11 13:50:44 -08003723static void set_advertising_complete(struct hci_dev *hdev, u8 status,
3724 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03003725{
3726 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07003727 struct hci_request req;
Florian Grandel7816b822015-06-18 03:16:45 +02003728 u8 instance;
3729 struct adv_info *adv_instance;
3730 int err;
Johan Hedberg4375f102013-09-25 13:26:10 +03003731
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303732 hci_dev_lock(hdev);
3733
Johan Hedberg4375f102013-09-25 13:26:10 +03003734 if (status) {
3735 u8 mgmt_err = mgmt_status(status);
3736
3737 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3738 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303739 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03003740 }
3741
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003742 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003743 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003744 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003745 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03003746
Johan Hedberg4375f102013-09-25 13:26:10 +03003747 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3748 &match);
3749
3750 new_settings(hdev, match.sk);
3751
3752 if (match.sk)
3753 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303754
Arman Uguray24b4f382015-03-23 15:57:12 -07003755 /* If "Set Advertising" was just disabled and instance advertising was
Florian Grandel7816b822015-06-18 03:16:45 +02003756 * set up earlier, then re-enable multi-instance advertising.
Arman Uguray24b4f382015-03-23 15:57:12 -07003757 */
3758 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
Florian Grandel7816b822015-06-18 03:16:45 +02003759 list_empty(&hdev->adv_instances))
Arman Uguray24b4f382015-03-23 15:57:12 -07003760 goto unlock;
3761
Florian Grandel7816b822015-06-18 03:16:45 +02003762 instance = hdev->cur_adv_instance;
3763 if (!instance) {
3764 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
3765 struct adv_info, list);
3766 if (!adv_instance)
3767 goto unlock;
3768
3769 instance = adv_instance->instance;
3770 }
3771
Arman Uguray24b4f382015-03-23 15:57:12 -07003772 hci_req_init(&req, hdev);
3773
Johan Hedbergf2252572015-11-18 12:49:20 +02003774 err = __hci_req_schedule_adv_instance(&req, instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07003775
Florian Grandel7816b822015-06-18 03:16:45 +02003776 if (!err)
3777 err = hci_req_run(&req, enable_advertising_instance);
3778
3779 if (err)
Arman Uguray24b4f382015-03-23 15:57:12 -07003780 BT_ERR("Failed to re-configure advertising");
3781
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05303782unlock:
3783 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03003784}
3785
Marcel Holtmann21b51872013-10-10 09:47:53 -07003786static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3787 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003788{
3789 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003790 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03003791 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003792 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003793 int err;
3794
3795 BT_DBG("request for %s", hdev->name);
3796
Johan Hedberge6fe7982013-10-02 15:45:22 +03003797 status = mgmt_le_support(hdev);
3798 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003799 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3800 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003801
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003802 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02003803 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3804 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03003805
3806 hci_dev_lock(hdev);
3807
3808 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03003809
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003810 /* The following conditions are ones which mean that we should
3811 * not do any HCI communication but directly send a mgmt
3812 * response to user space (after toggling the flag if
3813 * necessary).
3814 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003815 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003816 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
3817 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003818 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003819 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03003820 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003821 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03003822
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003823 if (cp->val) {
Johan Hedbergcab054a2015-11-30 11:21:45 +02003824 hdev->cur_adv_instance = 0x00;
Marcel Holtmann238be782015-03-13 02:11:06 -07003825 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003826 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003827 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003828 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003829 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003830 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07003831 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003832 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03003833 }
3834
3835 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3836 if (err < 0)
3837 goto unlock;
3838
3839 if (changed)
3840 err = new_settings(hdev, sk);
3841
3842 goto unlock;
3843 }
3844
Johan Hedberg333ae952015-03-17 13:48:47 +02003845 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3846 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003847 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3848 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03003849 goto unlock;
3850 }
3851
3852 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3853 if (!cmd) {
3854 err = -ENOMEM;
3855 goto unlock;
3856 }
3857
3858 hci_req_init(&req, hdev);
3859
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003860 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07003861 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003862 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07003863 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07003864
Florian Grandel7816b822015-06-18 03:16:45 +02003865 cancel_adv_timeout(hdev);
3866
Arman Uguray24b4f382015-03-23 15:57:12 -07003867 if (val) {
Florian Grandel7816b822015-06-18 03:16:45 +02003868 /* Switch to instance "0" for the Set Advertising setting.
3869 * We cannot use update_[adv|scan_rsp]_data() here as the
3870 * HCI_ADVERTISING flag is not yet set.
3871 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02003872 hdev->cur_adv_instance = 0x00;
Johan Hedbergf2252572015-11-18 12:49:20 +02003873 __hci_req_update_adv_data(&req, 0x00);
3874 __hci_req_update_scan_rsp_data(&req, 0x00);
3875 __hci_req_enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003876 } else {
Johan Hedbergf2252572015-11-18 12:49:20 +02003877 __hci_req_disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07003878 }
Johan Hedberg4375f102013-09-25 13:26:10 +03003879
3880 err = hci_req_run(&req, set_advertising_complete);
3881 if (err < 0)
3882 mgmt_pending_remove(cmd);
3883
3884unlock:
3885 hci_dev_unlock(hdev);
3886 return err;
3887}
3888
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003889static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3890 void *data, u16 len)
3891{
3892 struct mgmt_cp_set_static_address *cp = data;
3893 int err;
3894
3895 BT_DBG("%s", hdev->name);
3896
Marcel Holtmann62af4442013-10-02 22:10:32 -07003897 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003898 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3899 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003900
3901 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003902 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3903 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003904
3905 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3906 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02003907 return mgmt_cmd_status(sk, hdev->id,
3908 MGMT_OP_SET_STATIC_ADDRESS,
3909 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003910
3911 /* Two most significant bits shall be set */
3912 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003913 return mgmt_cmd_status(sk, hdev->id,
3914 MGMT_OP_SET_STATIC_ADDRESS,
3915 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003916 }
3917
3918 hci_dev_lock(hdev);
3919
3920 bacpy(&hdev->static_addr, &cp->bdaddr);
3921
Marcel Holtmann93690c22015-03-06 10:11:21 -08003922 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
3923 if (err < 0)
3924 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003925
Marcel Holtmann93690c22015-03-06 10:11:21 -08003926 err = new_settings(hdev, sk);
3927
3928unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003929 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003930 return err;
3931}
3932
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003933static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3934 void *data, u16 len)
3935{
3936 struct mgmt_cp_set_scan_params *cp = data;
3937 __u16 interval, window;
3938 int err;
3939
3940 BT_DBG("%s", hdev->name);
3941
3942 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02003943 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3944 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003945
3946 interval = __le16_to_cpu(cp->interval);
3947
3948 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003949 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3950 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003951
3952 window = __le16_to_cpu(cp->window);
3953
3954 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02003955 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3956 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003957
Marcel Holtmann899e1072013-10-14 09:55:32 -07003958 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02003959 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3960 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07003961
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003962 hci_dev_lock(hdev);
3963
3964 hdev->le_scan_interval = interval;
3965 hdev->le_scan_window = window;
3966
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003967 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
3968 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003969
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003970 /* If background scan is running, restart it so new parameters are
3971 * loaded.
3972 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003973 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003974 hdev->discovery.state == DISCOVERY_STOPPED) {
3975 struct hci_request req;
3976
3977 hci_req_init(&req, hdev);
3978
3979 hci_req_add_le_scan_disable(&req);
3980 hci_req_add_le_passive_scan(&req);
3981
3982 hci_req_run(&req, NULL);
3983 }
3984
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003985 hci_dev_unlock(hdev);
3986
3987 return err;
3988}
3989
Marcel Holtmann1904a852015-01-11 13:50:44 -08003990static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
3991 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05003992{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003993 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003994
3995 BT_DBG("status 0x%02x", status);
3996
3997 hci_dev_lock(hdev);
3998
Johan Hedberg333ae952015-03-17 13:48:47 +02003999 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004000 if (!cmd)
4001 goto unlock;
4002
4003 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004004 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4005 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004006 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004007 struct mgmt_mode *cp = cmd->param;
4008
4009 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004010 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004011 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004012 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004013
Johan Hedberg33e38b32013-03-15 17:07:05 -05004014 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4015 new_settings(hdev, cmd->sk);
4016 }
4017
4018 mgmt_pending_remove(cmd);
4019
4020unlock:
4021 hci_dev_unlock(hdev);
4022}
4023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004024static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004025 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004026{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004027 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004028 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004029 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004030 int err;
4031
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004032 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004033
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004034 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004035 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004036 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4037 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004038
Johan Hedberga7e80f22013-01-09 16:05:19 +02004039 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004040 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4041 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004042
Antti Julkuf6422ec2011-06-22 13:11:56 +03004043 hci_dev_lock(hdev);
4044
Johan Hedberg333ae952015-03-17 13:48:47 +02004045 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004046 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4047 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004048 goto unlock;
4049 }
4050
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004051 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004052 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4053 hdev);
4054 goto unlock;
4055 }
4056
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004057 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004058 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004059 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4060 hdev);
4061 new_settings(hdev, sk);
4062 goto unlock;
4063 }
4064
Johan Hedberg33e38b32013-03-15 17:07:05 -05004065 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4066 data, len);
4067 if (!cmd) {
4068 err = -ENOMEM;
4069 goto unlock;
4070 }
4071
4072 hci_req_init(&req, hdev);
4073
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004074 __hci_req_write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004075
4076 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004077 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004078 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4079 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004080 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004081 }
4082
Johan Hedberg33e38b32013-03-15 17:07:05 -05004083unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004084 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004085
Antti Julkuf6422ec2011-06-22 13:11:56 +03004086 return err;
4087}
4088
Marcel Holtmann1904a852015-01-11 13:50:44 -08004089static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004090{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004091 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004092
4093 BT_DBG("status 0x%02x", status);
4094
4095 hci_dev_lock(hdev);
4096
Johan Hedberg333ae952015-03-17 13:48:47 +02004097 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004098 if (!cmd)
4099 goto unlock;
4100
4101 if (status) {
4102 u8 mgmt_err = mgmt_status(status);
4103
4104 /* We need to restore the flag if related HCI commands
4105 * failed.
4106 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004107 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004108
Johan Hedberga69e8372015-03-06 21:08:53 +02004109 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004110 } else {
4111 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4112 new_settings(hdev, cmd->sk);
4113 }
4114
4115 mgmt_pending_remove(cmd);
4116
4117unlock:
4118 hci_dev_unlock(hdev);
4119}
4120
4121static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4122{
4123 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004124 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004125 struct hci_request req;
4126 int err;
4127
4128 BT_DBG("request for %s", hdev->name);
4129
4130 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004131 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4132 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004133
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004134 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004135 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4136 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004137
4138 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004139 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4140 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004141
4142 hci_dev_lock(hdev);
4143
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004144 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004145 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4146 goto unlock;
4147 }
4148
4149 if (!hdev_is_powered(hdev)) {
4150 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004151 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4152 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4153 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4154 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4155 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004156 }
4157
Marcel Holtmannce05d602015-03-13 02:11:03 -07004158 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004159
4160 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4161 if (err < 0)
4162 goto unlock;
4163
4164 err = new_settings(hdev, sk);
4165 goto unlock;
4166 }
4167
4168 /* Reject disabling when powered on */
4169 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004170 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4171 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004172 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004173 } else {
4174 /* When configuring a dual-mode controller to operate
4175 * with LE only and using a static address, then switching
4176 * BR/EDR back on is not allowed.
4177 *
4178 * Dual-mode controllers shall operate with the public
4179 * address as its identity address for BR/EDR and LE. So
4180 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004181 *
4182 * The same restrictions applies when secure connections
4183 * has been enabled. For BR/EDR this is a controller feature
4184 * while for LE it is a host stack feature. This means that
4185 * switching BR/EDR back on when secure connections has been
4186 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004187 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004188 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004189 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004190 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004191 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4192 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004193 goto unlock;
4194 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004195 }
4196
Johan Hedberg333ae952015-03-17 13:48:47 +02004197 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004198 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4199 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004200 goto unlock;
4201 }
4202
4203 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4204 if (!cmd) {
4205 err = -ENOMEM;
4206 goto unlock;
4207 }
4208
Johan Hedbergf2252572015-11-18 12:49:20 +02004209 /* We need to flip the bit already here so that
4210 * hci_req_update_adv_data generates the correct flags.
Johan Hedberg0663ca22013-10-02 13:43:14 +03004211 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004212 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004213
4214 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004215
Johan Hedbergbf943cb2015-11-25 16:15:43 +02004216 __hci_req_write_fast_connectable(&req, false);
Johan Hedberg01b1cb82015-11-16 12:52:21 +02004217 __hci_req_update_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004218
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004219 /* Since only the advertising data flags will change, there
4220 * is no need to update the scan response data.
4221 */
Johan Hedbergcab054a2015-11-30 11:21:45 +02004222 __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004223
Johan Hedberg0663ca22013-10-02 13:43:14 +03004224 err = hci_req_run(&req, set_bredr_complete);
4225 if (err < 0)
4226 mgmt_pending_remove(cmd);
4227
4228unlock:
4229 hci_dev_unlock(hdev);
4230 return err;
4231}
4232
Johan Hedberga1443f52015-01-23 15:42:46 +02004233static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4234{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004235 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004236 struct mgmt_mode *cp;
4237
4238 BT_DBG("%s status %u", hdev->name, status);
4239
4240 hci_dev_lock(hdev);
4241
Johan Hedberg333ae952015-03-17 13:48:47 +02004242 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004243 if (!cmd)
4244 goto unlock;
4245
4246 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004247 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4248 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004249 goto remove;
4250 }
4251
4252 cp = cmd->param;
4253
4254 switch (cp->val) {
4255 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004256 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4257 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004258 break;
4259 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004260 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004261 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004262 break;
4263 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004264 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4265 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004266 break;
4267 }
4268
4269 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4270 new_settings(hdev, cmd->sk);
4271
4272remove:
4273 mgmt_pending_remove(cmd);
4274unlock:
4275 hci_dev_unlock(hdev);
4276}
4277
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004278static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4279 void *data, u16 len)
4280{
4281 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004282 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004283 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004284 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004285 int err;
4286
4287 BT_DBG("request for %s", hdev->name);
4288
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004289 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004290 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004291 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4292 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004293
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004294 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004295 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004296 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004297 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4298 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004299
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004300 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004301 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004302 MGMT_STATUS_INVALID_PARAMS);
4303
4304 hci_dev_lock(hdev);
4305
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004306 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004307 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004308 bool changed;
4309
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004310 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004311 changed = !hci_dev_test_and_set_flag(hdev,
4312 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004313 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004314 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004315 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004316 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004317 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004318 changed = hci_dev_test_and_clear_flag(hdev,
4319 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004320 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004321 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004322
4323 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4324 if (err < 0)
4325 goto failed;
4326
4327 if (changed)
4328 err = new_settings(hdev, sk);
4329
4330 goto failed;
4331 }
4332
Johan Hedberg333ae952015-03-17 13:48:47 +02004333 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004334 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4335 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004336 goto failed;
4337 }
4338
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004339 val = !!cp->val;
4340
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004341 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4342 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004343 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4344 goto failed;
4345 }
4346
4347 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4348 if (!cmd) {
4349 err = -ENOMEM;
4350 goto failed;
4351 }
4352
Johan Hedberga1443f52015-01-23 15:42:46 +02004353 hci_req_init(&req, hdev);
4354 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4355 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004356 if (err < 0) {
4357 mgmt_pending_remove(cmd);
4358 goto failed;
4359 }
4360
4361failed:
4362 hci_dev_unlock(hdev);
4363 return err;
4364}
4365
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004366static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4367 void *data, u16 len)
4368{
4369 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004370 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004371 int err;
4372
4373 BT_DBG("request for %s", hdev->name);
4374
Johan Hedbergb97109792014-06-24 14:00:28 +03004375 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004376 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4377 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004378
4379 hci_dev_lock(hdev);
4380
4381 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004382 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004383 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004384 changed = hci_dev_test_and_clear_flag(hdev,
4385 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004386
Johan Hedbergb97109792014-06-24 14:00:28 +03004387 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004388 use_changed = !hci_dev_test_and_set_flag(hdev,
4389 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004390 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004391 use_changed = hci_dev_test_and_clear_flag(hdev,
4392 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004393
4394 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004395 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004396 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4397 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4398 sizeof(mode), &mode);
4399 }
4400
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004401 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4402 if (err < 0)
4403 goto unlock;
4404
4405 if (changed)
4406 err = new_settings(hdev, sk);
4407
4408unlock:
4409 hci_dev_unlock(hdev);
4410 return err;
4411}
4412
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004413static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4414 u16 len)
4415{
4416 struct mgmt_cp_set_privacy *cp = cp_data;
4417 bool changed;
4418 int err;
4419
4420 BT_DBG("request for %s", hdev->name);
4421
4422 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004423 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4424 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004425
4426 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004427 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4428 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004429
4430 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004431 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4432 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004433
4434 hci_dev_lock(hdev);
4435
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004436 /* If user space supports this command it is also expected to
4437 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4438 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004439 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004440
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004441 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004442 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004443 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004444 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004445 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004446 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004447 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004448 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004449 }
4450
4451 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4452 if (err < 0)
4453 goto unlock;
4454
4455 if (changed)
4456 err = new_settings(hdev, sk);
4457
4458unlock:
4459 hci_dev_unlock(hdev);
4460 return err;
4461}
4462
Johan Hedberg41edf162014-02-18 10:19:35 +02004463static bool irk_is_valid(struct mgmt_irk_info *irk)
4464{
4465 switch (irk->addr.type) {
4466 case BDADDR_LE_PUBLIC:
4467 return true;
4468
4469 case BDADDR_LE_RANDOM:
4470 /* Two most significant bits shall be set */
4471 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4472 return false;
4473 return true;
4474 }
4475
4476 return false;
4477}
4478
4479static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4480 u16 len)
4481{
4482 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004483 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
4484 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02004485 u16 irk_count, expected_len;
4486 int i, err;
4487
4488 BT_DBG("request for %s", hdev->name);
4489
4490 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004491 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4492 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02004493
4494 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004495 if (irk_count > max_irk_count) {
4496 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004497 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4498 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004499 }
Johan Hedberg41edf162014-02-18 10:19:35 +02004500
4501 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4502 if (expected_len != len) {
4503 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004504 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004505 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4506 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004507 }
4508
4509 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4510
4511 for (i = 0; i < irk_count; i++) {
4512 struct mgmt_irk_info *key = &cp->irks[i];
4513
4514 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004515 return mgmt_cmd_status(sk, hdev->id,
4516 MGMT_OP_LOAD_IRKS,
4517 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02004518 }
4519
4520 hci_dev_lock(hdev);
4521
4522 hci_smp_irks_clear(hdev);
4523
4524 for (i = 0; i < irk_count; i++) {
4525 struct mgmt_irk_info *irk = &cp->irks[i];
Johan Hedberg41edf162014-02-18 10:19:35 +02004526
Johan Hedberg85813a72015-10-21 18:02:59 +03004527 hci_add_irk(hdev, &irk->addr.bdaddr,
4528 le_addr_type(irk->addr.type), irk->val,
Johan Hedberg41edf162014-02-18 10:19:35 +02004529 BDADDR_ANY);
4530 }
4531
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004532 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02004533
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004534 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02004535
4536 hci_dev_unlock(hdev);
4537
4538 return err;
4539}
4540
Johan Hedberg3f706b72013-01-20 14:27:16 +02004541static bool ltk_is_valid(struct mgmt_ltk_info *key)
4542{
4543 if (key->master != 0x00 && key->master != 0x01)
4544 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004545
4546 switch (key->addr.type) {
4547 case BDADDR_LE_PUBLIC:
4548 return true;
4549
4550 case BDADDR_LE_RANDOM:
4551 /* Two most significant bits shall be set */
4552 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4553 return false;
4554 return true;
4555 }
4556
4557 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004558}
4559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004560static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004561 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004562{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004563 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03004564 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
4565 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004566 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004567 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004568
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004569 BT_DBG("request for %s", hdev->name);
4570
4571 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004572 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4573 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004574
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004575 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004576 if (key_count > max_key_count) {
4577 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02004578 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4579 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03004580 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004581
4582 expected_len = sizeof(*cp) + key_count *
4583 sizeof(struct mgmt_ltk_info);
4584 if (expected_len != len) {
4585 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02004586 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02004587 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4588 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004589 }
4590
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004591 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004592
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004593 for (i = 0; i < key_count; i++) {
4594 struct mgmt_ltk_info *key = &cp->keys[i];
4595
Johan Hedberg3f706b72013-01-20 14:27:16 +02004596 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02004597 return mgmt_cmd_status(sk, hdev->id,
4598 MGMT_OP_LOAD_LONG_TERM_KEYS,
4599 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004600 }
4601
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004602 hci_dev_lock(hdev);
4603
4604 hci_smp_ltks_clear(hdev);
4605
4606 for (i = 0; i < key_count; i++) {
4607 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedberg85813a72015-10-21 18:02:59 +03004608 u8 type, authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004609
Johan Hedberg61b43352014-05-29 19:36:53 +03004610 switch (key->type) {
4611 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004612 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004613 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004614 break;
4615 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03004616 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004617 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03004618 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03004619 case MGMT_LTK_P256_UNAUTH:
4620 authenticated = 0x00;
4621 type = SMP_LTK_P256;
4622 break;
4623 case MGMT_LTK_P256_AUTH:
4624 authenticated = 0x01;
4625 type = SMP_LTK_P256;
4626 break;
4627 case MGMT_LTK_P256_DEBUG:
4628 authenticated = 0x00;
4629 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03004630 default:
4631 continue;
4632 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03004633
Johan Hedberg85813a72015-10-21 18:02:59 +03004634 hci_add_ltk(hdev, &key->addr.bdaddr,
4635 le_addr_type(key->addr.type), type, authenticated,
4636 key->val, key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004637 }
4638
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004639 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004640 NULL, 0);
4641
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004642 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004643
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004644 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004645}
4646
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004647static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004648{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004649 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004650 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02004651 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004652
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004653 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004654
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004655 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004656 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004657 rp.tx_power = conn->tx_power;
4658 rp.max_tx_power = conn->max_tx_power;
4659 } else {
4660 rp.rssi = HCI_RSSI_INVALID;
4661 rp.tx_power = HCI_TX_POWER_INVALID;
4662 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004663 }
4664
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004665 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
4666 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004667
4668 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004669 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02004670
4671 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004672}
4673
Marcel Holtmann1904a852015-01-11 13:50:44 -08004674static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
4675 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004676{
4677 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004678 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004679 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004680 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004681 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004682
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004683 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004684
4685 hci_dev_lock(hdev);
4686
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004687 /* Commands sent in request are either Read RSSI or Read Transmit Power
4688 * Level so we check which one was last sent to retrieve connection
4689 * handle. Both commands have handle as first parameter so it's safe to
4690 * cast data on the same command struct.
4691 *
4692 * First command sent is always Read RSSI and we fail only if it fails.
4693 * In other case we simply override error to indicate success as we
4694 * already remembered if TX power value is actually valid.
4695 */
4696 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
4697 if (!cp) {
4698 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004699 status = MGMT_STATUS_SUCCESS;
4700 } else {
4701 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004702 }
4703
4704 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004705 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004706 goto unlock;
4707 }
4708
4709 handle = __le16_to_cpu(cp->handle);
4710 conn = hci_conn_hash_lookup_handle(hdev, handle);
4711 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004712 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004713 goto unlock;
4714 }
4715
Johan Hedberg333ae952015-03-17 13:48:47 +02004716 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004717 if (!cmd)
4718 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004719
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004720 cmd->cmd_complete(cmd, status);
4721 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004722
4723unlock:
4724 hci_dev_unlock(hdev);
4725}
4726
4727static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
4728 u16 len)
4729{
4730 struct mgmt_cp_get_conn_info *cp = data;
4731 struct mgmt_rp_get_conn_info rp;
4732 struct hci_conn *conn;
4733 unsigned long conn_info_age;
4734 int err = 0;
4735
4736 BT_DBG("%s", hdev->name);
4737
4738 memset(&rp, 0, sizeof(rp));
4739 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4740 rp.addr.type = cp->addr.type;
4741
4742 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004743 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4744 MGMT_STATUS_INVALID_PARAMS,
4745 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004746
4747 hci_dev_lock(hdev);
4748
4749 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004750 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4751 MGMT_STATUS_NOT_POWERED, &rp,
4752 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004753 goto unlock;
4754 }
4755
4756 if (cp->addr.type == BDADDR_BREDR)
4757 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4758 &cp->addr.bdaddr);
4759 else
4760 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
4761
4762 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004763 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4764 MGMT_STATUS_NOT_CONNECTED, &rp,
4765 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004766 goto unlock;
4767 }
4768
Johan Hedberg333ae952015-03-17 13:48:47 +02004769 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004770 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4771 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004772 goto unlock;
4773 }
4774
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004775 /* To avoid client trying to guess when to poll again for information we
4776 * calculate conn info age as random value between min/max set in hdev.
4777 */
4778 conn_info_age = hdev->conn_info_min_age +
4779 prandom_u32_max(hdev->conn_info_max_age -
4780 hdev->conn_info_min_age);
4781
4782 /* Query controller to refresh cached values if they are too old or were
4783 * never read.
4784 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02004785 if (time_after(jiffies, conn->conn_info_timestamp +
4786 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004787 !conn->conn_info_timestamp) {
4788 struct hci_request req;
4789 struct hci_cp_read_tx_power req_txp_cp;
4790 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004791 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004792
4793 hci_req_init(&req, hdev);
4794 req_rssi_cp.handle = cpu_to_le16(conn->handle);
4795 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
4796 &req_rssi_cp);
4797
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02004798 /* For LE links TX power does not change thus we don't need to
4799 * query for it once value is known.
4800 */
4801 if (!bdaddr_type_is_le(cp->addr.type) ||
4802 conn->tx_power == HCI_TX_POWER_INVALID) {
4803 req_txp_cp.handle = cpu_to_le16(conn->handle);
4804 req_txp_cp.type = 0x00;
4805 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4806 sizeof(req_txp_cp), &req_txp_cp);
4807 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004808
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004809 /* Max TX power needs to be read only once per connection */
4810 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
4811 req_txp_cp.handle = cpu_to_le16(conn->handle);
4812 req_txp_cp.type = 0x01;
4813 hci_req_add(&req, HCI_OP_READ_TX_POWER,
4814 sizeof(req_txp_cp), &req_txp_cp);
4815 }
4816
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004817 err = hci_req_run(&req, conn_info_refresh_complete);
4818 if (err < 0)
4819 goto unlock;
4820
4821 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
4822 data, len);
4823 if (!cmd) {
4824 err = -ENOMEM;
4825 goto unlock;
4826 }
4827
4828 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004829 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02004830 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004831
4832 conn->conn_info_timestamp = jiffies;
4833 } else {
4834 /* Cache is valid, just reply with values cached in hci_conn */
4835 rp.rssi = conn->rssi;
4836 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02004837 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004838
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004839 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
4840 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02004841 }
4842
4843unlock:
4844 hci_dev_unlock(hdev);
4845 return err;
4846}
4847
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004848static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02004849{
4850 struct hci_conn *conn = cmd->user_data;
4851 struct mgmt_rp_get_clock_info rp;
4852 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02004853 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02004854
4855 memset(&rp, 0, sizeof(rp));
4856 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
4857
4858 if (status)
4859 goto complete;
4860
4861 hdev = hci_dev_get(cmd->index);
4862 if (hdev) {
4863 rp.local_clock = cpu_to_le32(hdev->clock);
4864 hci_dev_put(hdev);
4865 }
4866
4867 if (conn) {
4868 rp.piconet_clock = cpu_to_le32(conn->clock);
4869 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
4870 }
4871
4872complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004873 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
4874 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02004875
4876 if (conn) {
4877 hci_conn_drop(conn);
4878 hci_conn_put(conn);
4879 }
Johan Hedberg9df74652014-12-19 22:26:03 +02004880
4881 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02004882}
4883
Marcel Holtmann1904a852015-01-11 13:50:44 -08004884static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03004885{
Johan Hedberg95868422014-06-28 17:54:07 +03004886 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004887 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004888 struct hci_conn *conn;
4889
4890 BT_DBG("%s status %u", hdev->name, status);
4891
4892 hci_dev_lock(hdev);
4893
4894 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
4895 if (!hci_cp)
4896 goto unlock;
4897
4898 if (hci_cp->which) {
4899 u16 handle = __le16_to_cpu(hci_cp->handle);
4900 conn = hci_conn_hash_lookup_handle(hdev, handle);
4901 } else {
4902 conn = NULL;
4903 }
4904
Johan Hedberg333ae952015-03-17 13:48:47 +02004905 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004906 if (!cmd)
4907 goto unlock;
4908
Johan Hedberg69487372014-12-05 13:36:07 +02004909 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03004910 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03004911
4912unlock:
4913 hci_dev_unlock(hdev);
4914}
4915
4916static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
4917 u16 len)
4918{
4919 struct mgmt_cp_get_clock_info *cp = data;
4920 struct mgmt_rp_get_clock_info rp;
4921 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004922 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03004923 struct hci_request req;
4924 struct hci_conn *conn;
4925 int err;
4926
4927 BT_DBG("%s", hdev->name);
4928
4929 memset(&rp, 0, sizeof(rp));
4930 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4931 rp.addr.type = cp->addr.type;
4932
4933 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004934 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4935 MGMT_STATUS_INVALID_PARAMS,
4936 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004937
4938 hci_dev_lock(hdev);
4939
4940 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004941 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
4942 MGMT_STATUS_NOT_POWERED, &rp,
4943 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004944 goto unlock;
4945 }
4946
4947 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
4948 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
4949 &cp->addr.bdaddr);
4950 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004951 err = mgmt_cmd_complete(sk, hdev->id,
4952 MGMT_OP_GET_CLOCK_INFO,
4953 MGMT_STATUS_NOT_CONNECTED,
4954 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03004955 goto unlock;
4956 }
4957 } else {
4958 conn = NULL;
4959 }
4960
4961 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
4962 if (!cmd) {
4963 err = -ENOMEM;
4964 goto unlock;
4965 }
4966
Johan Hedberg69487372014-12-05 13:36:07 +02004967 cmd->cmd_complete = clock_info_cmd_complete;
4968
Johan Hedberg95868422014-06-28 17:54:07 +03004969 hci_req_init(&req, hdev);
4970
4971 memset(&hci_cp, 0, sizeof(hci_cp));
4972 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4973
4974 if (conn) {
4975 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03004976 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03004977
4978 hci_cp.handle = cpu_to_le16(conn->handle);
4979 hci_cp.which = 0x01; /* Piconet clock */
4980 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
4981 }
4982
4983 err = hci_req_run(&req, get_clock_info_complete);
4984 if (err < 0)
4985 mgmt_pending_remove(cmd);
4986
4987unlock:
4988 hci_dev_unlock(hdev);
4989 return err;
4990}
4991
Johan Hedberg5a154e62014-12-19 22:26:02 +02004992static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
4993{
4994 struct hci_conn *conn;
4995
4996 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
4997 if (!conn)
4998 return false;
4999
5000 if (conn->dst_type != type)
5001 return false;
5002
5003 if (conn->state != BT_CONNECTED)
5004 return false;
5005
5006 return true;
5007}
5008
5009/* This function requires the caller holds hdev->lock */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005010static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
Johan Hedberg5a154e62014-12-19 22:26:02 +02005011 u8 addr_type, u8 auto_connect)
5012{
Johan Hedberg5a154e62014-12-19 22:26:02 +02005013 struct hci_conn_params *params;
5014
5015 params = hci_conn_params_add(hdev, addr, addr_type);
5016 if (!params)
5017 return -EIO;
5018
5019 if (params->auto_connect == auto_connect)
5020 return 0;
5021
5022 list_del_init(&params->action);
5023
5024 switch (auto_connect) {
5025 case HCI_AUTO_CONN_DISABLED:
5026 case HCI_AUTO_CONN_LINK_LOSS:
Jakub Pawlowski28a667c2015-08-07 20:22:54 +02005027 /* If auto connect is being disabled when we're trying to
5028 * connect to device, keep connecting.
5029 */
5030 if (params->explicit_connect)
5031 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005032 break;
5033 case HCI_AUTO_CONN_REPORT:
Johan Hedberg49c50922015-10-16 10:07:51 +03005034 if (params->explicit_connect)
5035 list_add(&params->action, &hdev->pend_le_conns);
5036 else
5037 list_add(&params->action, &hdev->pend_le_reports);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005038 break;
5039 case HCI_AUTO_CONN_DIRECT:
5040 case HCI_AUTO_CONN_ALWAYS:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005041 if (!is_connected(hdev, addr, addr_type))
Johan Hedberg5a154e62014-12-19 22:26:02 +02005042 list_add(&params->action, &hdev->pend_le_conns);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005043 break;
5044 }
5045
5046 params->auto_connect = auto_connect;
5047
5048 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5049 auto_connect);
5050
5051 return 0;
5052}
5053
Marcel Holtmann8afef092014-06-29 22:28:34 +02005054static void device_added(struct sock *sk, struct hci_dev *hdev,
5055 bdaddr_t *bdaddr, u8 type, u8 action)
5056{
5057 struct mgmt_ev_device_added ev;
5058
5059 bacpy(&ev.addr.bdaddr, bdaddr);
5060 ev.addr.type = type;
5061 ev.action = action;
5062
5063 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5064}
5065
Marcel Holtmann2faade52014-06-29 19:44:03 +02005066static int add_device(struct sock *sk, struct hci_dev *hdev,
5067 void *data, u16 len)
5068{
5069 struct mgmt_cp_add_device *cp = data;
5070 u8 auto_conn, addr_type;
5071 int err;
5072
5073 BT_DBG("%s", hdev->name);
5074
Johan Hedberg66593582014-07-09 12:59:14 +03005075 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005076 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005077 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5078 MGMT_STATUS_INVALID_PARAMS,
5079 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005080
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005081 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005082 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5083 MGMT_STATUS_INVALID_PARAMS,
5084 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005085
5086 hci_dev_lock(hdev);
5087
Johan Hedberg66593582014-07-09 12:59:14 +03005088 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005089 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005090 if (cp->action != 0x01) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005091 err = mgmt_cmd_complete(sk, hdev->id,
5092 MGMT_OP_ADD_DEVICE,
5093 MGMT_STATUS_INVALID_PARAMS,
5094 &cp->addr, sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005095 goto unlock;
5096 }
5097
5098 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5099 cp->addr.type);
5100 if (err)
5101 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005102
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005103 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005104
Johan Hedberg66593582014-07-09 12:59:14 +03005105 goto added;
5106 }
5107
Johan Hedberg85813a72015-10-21 18:02:59 +03005108 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005109
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005110 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005111 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005112 else if (cp->action == 0x01)
5113 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005114 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005115 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005116
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005117 /* Kernel internally uses conn_params with resolvable private
5118 * address, but Add Device allows only identity addresses.
5119 * Make sure it is enforced before calling
5120 * hci_conn_params_lookup.
5121 */
5122 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005123 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5124 MGMT_STATUS_INVALID_PARAMS,
5125 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005126 goto unlock;
5127 }
5128
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005129 /* If the connection parameters don't exist for this device,
5130 * they will be created and configured with defaults.
5131 */
Johan Hedberg51d7a942015-11-11 08:11:18 +02005132 if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005133 auto_conn) < 0) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005134 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5135 MGMT_STATUS_FAILED, &cp->addr,
5136 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005137 goto unlock;
5138 }
5139
Johan Hedberg51d7a942015-11-11 08:11:18 +02005140 hci_update_background_scan(hdev);
5141
Johan Hedberg66593582014-07-09 12:59:14 +03005142added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005143 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5144
Johan Hedberg51d7a942015-11-11 08:11:18 +02005145 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5146 MGMT_STATUS_SUCCESS, &cp->addr,
5147 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005148
5149unlock:
5150 hci_dev_unlock(hdev);
5151 return err;
5152}
5153
Marcel Holtmann8afef092014-06-29 22:28:34 +02005154static void device_removed(struct sock *sk, struct hci_dev *hdev,
5155 bdaddr_t *bdaddr, u8 type)
5156{
5157 struct mgmt_ev_device_removed ev;
5158
5159 bacpy(&ev.addr.bdaddr, bdaddr);
5160 ev.addr.type = type;
5161
5162 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5163}
5164
Marcel Holtmann2faade52014-06-29 19:44:03 +02005165static int remove_device(struct sock *sk, struct hci_dev *hdev,
5166 void *data, u16 len)
5167{
5168 struct mgmt_cp_remove_device *cp = data;
5169 int err;
5170
5171 BT_DBG("%s", hdev->name);
5172
5173 hci_dev_lock(hdev);
5174
5175 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005176 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005177 u8 addr_type;
5178
Johan Hedberg66593582014-07-09 12:59:14 +03005179 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005180 err = mgmt_cmd_complete(sk, hdev->id,
5181 MGMT_OP_REMOVE_DEVICE,
5182 MGMT_STATUS_INVALID_PARAMS,
5183 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005184 goto unlock;
5185 }
5186
Johan Hedberg66593582014-07-09 12:59:14 +03005187 if (cp->addr.type == BDADDR_BREDR) {
5188 err = hci_bdaddr_list_del(&hdev->whitelist,
5189 &cp->addr.bdaddr,
5190 cp->addr.type);
5191 if (err) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005192 err = mgmt_cmd_complete(sk, hdev->id,
5193 MGMT_OP_REMOVE_DEVICE,
5194 MGMT_STATUS_INVALID_PARAMS,
5195 &cp->addr,
5196 sizeof(cp->addr));
Johan Hedberg66593582014-07-09 12:59:14 +03005197 goto unlock;
5198 }
5199
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005200 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005201
Johan Hedberg66593582014-07-09 12:59:14 +03005202 device_removed(sk, hdev, &cp->addr.bdaddr,
5203 cp->addr.type);
5204 goto complete;
5205 }
5206
Johan Hedberg85813a72015-10-21 18:02:59 +03005207 addr_type = le_addr_type(cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005208
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005209 /* Kernel internally uses conn_params with resolvable private
5210 * address, but Remove Device allows only identity addresses.
5211 * Make sure it is enforced before calling
5212 * hci_conn_params_lookup.
5213 */
5214 if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005215 err = mgmt_cmd_complete(sk, hdev->id,
5216 MGMT_OP_REMOVE_DEVICE,
5217 MGMT_STATUS_INVALID_PARAMS,
5218 &cp->addr, sizeof(cp->addr));
Jakub Pawlowski9a0a8a82015-07-20 13:12:49 +02005219 goto unlock;
5220 }
5221
Johan Hedbergc71593d2014-07-02 17:37:28 +03005222 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5223 addr_type);
5224 if (!params) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005225 err = mgmt_cmd_complete(sk, hdev->id,
5226 MGMT_OP_REMOVE_DEVICE,
5227 MGMT_STATUS_INVALID_PARAMS,
5228 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005229 goto unlock;
5230 }
5231
Johan Hedberg679d2b62015-10-16 10:07:52 +03005232 if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
5233 params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005234 err = mgmt_cmd_complete(sk, hdev->id,
5235 MGMT_OP_REMOVE_DEVICE,
5236 MGMT_STATUS_INVALID_PARAMS,
5237 &cp->addr, sizeof(cp->addr));
Johan Hedbergc71593d2014-07-02 17:37:28 +03005238 goto unlock;
5239 }
5240
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005241 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005242 list_del(&params->list);
5243 kfree(params);
Johan Hedberg51d7a942015-11-11 08:11:18 +02005244 hci_update_background_scan(hdev);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005245
5246 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005247 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005248 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005249 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005250
Marcel Holtmann2faade52014-06-29 19:44:03 +02005251 if (cp->addr.type) {
Johan Hedberg51d7a942015-11-11 08:11:18 +02005252 err = mgmt_cmd_complete(sk, hdev->id,
5253 MGMT_OP_REMOVE_DEVICE,
5254 MGMT_STATUS_INVALID_PARAMS,
5255 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005256 goto unlock;
5257 }
5258
Johan Hedberg66593582014-07-09 12:59:14 +03005259 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5260 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5261 list_del(&b->list);
5262 kfree(b);
5263 }
5264
Johan Hedberg01b1cb82015-11-16 12:52:21 +02005265 hci_req_update_scan(hdev);
Johan Hedberga3974072014-07-09 12:59:15 +03005266
Johan Hedberg19de0822014-07-06 13:06:51 +03005267 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5268 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5269 continue;
5270 device_removed(sk, hdev, &p->addr, p->addr_type);
Johan Hedberg679d2b62015-10-16 10:07:52 +03005271 if (p->explicit_connect) {
5272 p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
5273 continue;
5274 }
Johan Hedberg19de0822014-07-06 13:06:51 +03005275 list_del(&p->action);
5276 list_del(&p->list);
5277 kfree(p);
5278 }
5279
5280 BT_DBG("All LE connection parameters were removed");
5281
Johan Hedberg51d7a942015-11-11 08:11:18 +02005282 hci_update_background_scan(hdev);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005283 }
5284
Johan Hedberg66593582014-07-09 12:59:14 +03005285complete:
Johan Hedberg51d7a942015-11-11 08:11:18 +02005286 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
5287 MGMT_STATUS_SUCCESS, &cp->addr,
5288 sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005289unlock:
5290 hci_dev_unlock(hdev);
5291 return err;
5292}
5293
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005294static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5295 u16 len)
5296{
5297 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005298 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5299 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005300 u16 param_count, expected_len;
5301 int i;
5302
5303 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005304 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5305 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005306
5307 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005308 if (param_count > max_param_count) {
5309 BT_ERR("load_conn_param: too big param_count value %u",
5310 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005311 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5312 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005313 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005314
5315 expected_len = sizeof(*cp) + param_count *
5316 sizeof(struct mgmt_conn_param);
5317 if (expected_len != len) {
5318 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5319 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005320 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5321 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005322 }
5323
5324 BT_DBG("%s param_count %u", hdev->name, param_count);
5325
5326 hci_dev_lock(hdev);
5327
5328 hci_conn_params_clear_disabled(hdev);
5329
5330 for (i = 0; i < param_count; i++) {
5331 struct mgmt_conn_param *param = &cp->params[i];
5332 struct hci_conn_params *hci_param;
5333 u16 min, max, latency, timeout;
5334 u8 addr_type;
5335
5336 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5337 param->addr.type);
5338
5339 if (param->addr.type == BDADDR_LE_PUBLIC) {
5340 addr_type = ADDR_LE_DEV_PUBLIC;
5341 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5342 addr_type = ADDR_LE_DEV_RANDOM;
5343 } else {
5344 BT_ERR("Ignoring invalid connection parameters");
5345 continue;
5346 }
5347
5348 min = le16_to_cpu(param->min_interval);
5349 max = le16_to_cpu(param->max_interval);
5350 latency = le16_to_cpu(param->latency);
5351 timeout = le16_to_cpu(param->timeout);
5352
5353 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
5354 min, max, latency, timeout);
5355
5356 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
5357 BT_ERR("Ignoring invalid connection parameters");
5358 continue;
5359 }
5360
5361 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
5362 addr_type);
5363 if (!hci_param) {
5364 BT_ERR("Failed to add connection parameters");
5365 continue;
5366 }
5367
5368 hci_param->conn_min_interval = min;
5369 hci_param->conn_max_interval = max;
5370 hci_param->conn_latency = latency;
5371 hci_param->supervision_timeout = timeout;
5372 }
5373
5374 hci_dev_unlock(hdev);
5375
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005376 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
5377 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005378}
5379
Marcel Holtmanndbece372014-07-04 18:11:55 +02005380static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5381 void *data, u16 len)
5382{
5383 struct mgmt_cp_set_external_config *cp = data;
5384 bool changed;
5385 int err;
5386
5387 BT_DBG("%s", hdev->name);
5388
5389 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005390 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5391 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005392
5393 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005394 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5395 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005396
5397 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02005398 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5399 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005400
5401 hci_dev_lock(hdev);
5402
5403 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07005404 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005405 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005406 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02005407
5408 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5409 if (err < 0)
5410 goto unlock;
5411
5412 if (!changed)
5413 goto unlock;
5414
Marcel Holtmannf4537c02014-07-04 19:06:23 +02005415 err = new_options(hdev, sk);
5416
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005417 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02005418 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005419
Marcel Holtmann516018a2015-03-13 02:11:04 -07005420 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005421 hci_dev_set_flag(hdev, HCI_CONFIG);
5422 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005423
5424 queue_work(hdev->req_workqueue, &hdev->power_on);
5425 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02005426 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02005427 mgmt_index_added(hdev);
5428 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02005429 }
5430
5431unlock:
5432 hci_dev_unlock(hdev);
5433 return err;
5434}
5435
Marcel Holtmann9713c172014-07-06 12:11:15 +02005436static int set_public_address(struct sock *sk, struct hci_dev *hdev,
5437 void *data, u16 len)
5438{
5439 struct mgmt_cp_set_public_address *cp = data;
5440 bool changed;
5441 int err;
5442
5443 BT_DBG("%s", hdev->name);
5444
5445 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005446 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5447 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005448
5449 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02005450 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5451 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005452
5453 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02005454 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
5455 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005456
5457 hci_dev_lock(hdev);
5458
5459 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
5460 bacpy(&hdev->public_addr, &cp->bdaddr);
5461
5462 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
5463 if (err < 0)
5464 goto unlock;
5465
5466 if (!changed)
5467 goto unlock;
5468
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005469 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02005470 err = new_options(hdev, sk);
5471
5472 if (is_configured(hdev)) {
5473 mgmt_index_removed(hdev);
5474
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005475 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005476
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005477 hci_dev_set_flag(hdev, HCI_CONFIG);
5478 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02005479
5480 queue_work(hdev->req_workqueue, &hdev->power_on);
5481 }
5482
5483unlock:
5484 hci_dev_unlock(hdev);
5485 return err;
5486}
5487
Marcel Holtmannbea41602015-03-14 22:43:17 -07005488static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5489 u8 data_len)
5490{
5491 eir[eir_len++] = sizeof(type) + data_len;
5492 eir[eir_len++] = type;
5493 memcpy(&eir[eir_len], data, data_len);
5494 eir_len += data_len;
5495
5496 return eir_len;
5497}
5498
Johan Hedberg40f66c02015-04-07 21:52:22 +03005499static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
5500 u16 opcode, struct sk_buff *skb)
5501{
5502 const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
5503 struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
5504 u8 *h192, *r192, *h256, *r256;
5505 struct mgmt_pending_cmd *cmd;
5506 u16 eir_len;
5507 int err;
5508
5509 BT_DBG("%s status %u", hdev->name, status);
5510
5511 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
5512 if (!cmd)
5513 return;
5514
5515 mgmt_cp = cmd->param;
5516
5517 if (status) {
5518 status = mgmt_status(status);
5519 eir_len = 0;
5520
5521 h192 = NULL;
5522 r192 = NULL;
5523 h256 = NULL;
5524 r256 = NULL;
5525 } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
5526 struct hci_rp_read_local_oob_data *rp;
5527
5528 if (skb->len != sizeof(*rp)) {
5529 status = MGMT_STATUS_FAILED;
5530 eir_len = 0;
5531 } else {
5532 status = MGMT_STATUS_SUCCESS;
5533 rp = (void *)skb->data;
5534
5535 eir_len = 5 + 18 + 18;
5536 h192 = rp->hash;
5537 r192 = rp->rand;
5538 h256 = NULL;
5539 r256 = NULL;
5540 }
5541 } else {
5542 struct hci_rp_read_local_oob_ext_data *rp;
5543
5544 if (skb->len != sizeof(*rp)) {
5545 status = MGMT_STATUS_FAILED;
5546 eir_len = 0;
5547 } else {
5548 status = MGMT_STATUS_SUCCESS;
5549 rp = (void *)skb->data;
5550
5551 if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
5552 eir_len = 5 + 18 + 18;
5553 h192 = NULL;
5554 r192 = NULL;
5555 } else {
5556 eir_len = 5 + 18 + 18 + 18 + 18;
5557 h192 = rp->hash192;
5558 r192 = rp->rand192;
5559 }
5560
5561 h256 = rp->hash256;
5562 r256 = rp->rand256;
5563 }
5564 }
5565
5566 mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
5567 if (!mgmt_rp)
5568 goto done;
5569
5570 if (status)
5571 goto send_rsp;
5572
5573 eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
5574 hdev->dev_class, 3);
5575
5576 if (h192 && r192) {
5577 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5578 EIR_SSP_HASH_C192, h192, 16);
5579 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5580 EIR_SSP_RAND_R192, r192, 16);
5581 }
5582
5583 if (h256 && r256) {
5584 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5585 EIR_SSP_HASH_C256, h256, 16);
5586 eir_len = eir_append_data(mgmt_rp->eir, eir_len,
5587 EIR_SSP_RAND_R256, r256, 16);
5588 }
5589
5590send_rsp:
5591 mgmt_rp->type = mgmt_cp->type;
5592 mgmt_rp->eir_len = cpu_to_le16(eir_len);
5593
5594 err = mgmt_cmd_complete(cmd->sk, hdev->id,
5595 MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
5596 mgmt_rp, sizeof(*mgmt_rp) + eir_len);
5597 if (err < 0 || status)
5598 goto done;
5599
5600 hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
5601
5602 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5603 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
5604 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
5605done:
5606 kfree(mgmt_rp);
5607 mgmt_pending_remove(cmd);
5608}
5609
5610static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
5611 struct mgmt_cp_read_local_oob_ext_data *cp)
5612{
5613 struct mgmt_pending_cmd *cmd;
5614 struct hci_request req;
5615 int err;
5616
5617 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
5618 cp, sizeof(*cp));
5619 if (!cmd)
5620 return -ENOMEM;
5621
5622 hci_req_init(&req, hdev);
5623
5624 if (bredr_sc_enabled(hdev))
5625 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
5626 else
5627 hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
5628
5629 err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
5630 if (err < 0) {
5631 mgmt_pending_remove(cmd);
5632 return err;
5633 }
5634
5635 return 0;
5636}
5637
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005638static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
5639 void *data, u16 data_len)
5640{
5641 struct mgmt_cp_read_local_oob_ext_data *cp = data;
5642 struct mgmt_rp_read_local_oob_ext_data *rp;
5643 size_t rp_len;
5644 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005645 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005646 int err;
5647
5648 BT_DBG("%s", hdev->name);
5649
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005650 if (hdev_is_powered(hdev)) {
5651 switch (cp->type) {
5652 case BIT(BDADDR_BREDR):
5653 status = mgmt_bredr_support(hdev);
5654 if (status)
5655 eir_len = 0;
5656 else
5657 eir_len = 5;
5658 break;
5659 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
5660 status = mgmt_le_support(hdev);
5661 if (status)
5662 eir_len = 0;
5663 else
5664 eir_len = 9 + 3 + 18 + 18 + 3;
5665 break;
5666 default:
5667 status = MGMT_STATUS_INVALID_PARAMS;
5668 eir_len = 0;
5669 break;
5670 }
5671 } else {
5672 status = MGMT_STATUS_NOT_POWERED;
5673 eir_len = 0;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005674 }
5675
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005676 rp_len = sizeof(*rp) + eir_len;
5677 rp = kmalloc(rp_len, GFP_ATOMIC);
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005678 if (!rp)
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005679 return -ENOMEM;
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005680
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005681 if (status)
5682 goto complete;
5683
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005684 hci_dev_lock(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005685
5686 eir_len = 0;
5687 switch (cp->type) {
5688 case BIT(BDADDR_BREDR):
Johan Hedberg40f66c02015-04-07 21:52:22 +03005689 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
5690 err = read_local_ssp_oob_req(hdev, sk, cp);
5691 hci_dev_unlock(hdev);
5692 if (!err)
5693 goto done;
5694
5695 status = MGMT_STATUS_FAILED;
5696 goto complete;
5697 } else {
5698 eir_len = eir_append_data(rp->eir, eir_len,
5699 EIR_CLASS_OF_DEV,
5700 hdev->dev_class, 3);
5701 }
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005702 break;
5703 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07005704 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5705 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005706 hci_dev_unlock(hdev);
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005707 status = MGMT_STATUS_FAILED;
5708 goto complete;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005709 }
5710
Marcel Holtmanne2135682015-04-02 12:00:58 -07005711 /* This should return the active RPA, but since the RPA
5712 * is only programmed on demand, it is really hard to fill
5713 * this in at the moment. For now disallow retrieving
5714 * local out-of-band data when privacy is in use.
5715 *
5716 * Returning the identity address will not help here since
5717 * pairing happens before the identity resolving key is
5718 * known and thus the connection establishment happens
5719 * based on the RPA and not the identity address.
5720 */
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005721 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
Marcel Holtmanne2135682015-04-02 12:00:58 -07005722 hci_dev_unlock(hdev);
5723 status = MGMT_STATUS_REJECTED;
5724 goto complete;
5725 }
5726
5727 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
5728 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
5729 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
5730 bacmp(&hdev->static_addr, BDADDR_ANY))) {
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005731 memcpy(addr, &hdev->static_addr, 6);
5732 addr[6] = 0x01;
5733 } else {
5734 memcpy(addr, &hdev->bdaddr, 6);
5735 addr[6] = 0x00;
5736 }
5737
5738 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
5739 addr, sizeof(addr));
5740
5741 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
5742 role = 0x02;
5743 else
5744 role = 0x01;
5745
5746 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
5747 &role, sizeof(role));
5748
Marcel Holtmann5082a592015-03-16 12:39:00 -07005749 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
5750 eir_len = eir_append_data(rp->eir, eir_len,
5751 EIR_LE_SC_CONFIRM,
5752 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005753
Marcel Holtmann5082a592015-03-16 12:39:00 -07005754 eir_len = eir_append_data(rp->eir, eir_len,
5755 EIR_LE_SC_RANDOM,
5756 rand, sizeof(rand));
5757 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005758
Johan Hedbergf2252572015-11-18 12:49:20 +02005759 flags = mgmt_get_adv_discov_flags(hdev);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005760
5761 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
5762 flags |= LE_AD_NO_BREDR;
5763
5764 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
5765 &flags, sizeof(flags));
5766 break;
5767 }
5768
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005769 hci_dev_unlock(hdev);
5770
Marcel Holtmann72000df2015-03-16 16:11:21 -07005771 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
5772
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005773 status = MGMT_STATUS_SUCCESS;
5774
5775complete:
Marcel Holtmannefcd8c92015-03-28 15:18:58 -07005776 rp->type = cp->type;
5777 rp->eir_len = cpu_to_le16(eir_len);
5778
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005779 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann57b0d3e2015-03-28 15:18:59 -07005780 status, rp, sizeof(*rp) + eir_len);
5781 if (err < 0 || status)
Marcel Holtmann72000df2015-03-16 16:11:21 -07005782 goto done;
5783
5784 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
5785 rp, sizeof(*rp) + eir_len,
5786 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005787
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07005788done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07005789 kfree(rp);
5790
5791 return err;
5792}
5793
Arman Uguray089fa8c2015-03-25 18:53:45 -07005794static u32 get_supported_adv_flags(struct hci_dev *hdev)
5795{
5796 u32 flags = 0;
5797
5798 flags |= MGMT_ADV_FLAG_CONNECTABLE;
5799 flags |= MGMT_ADV_FLAG_DISCOV;
5800 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
5801 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
5802
5803 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
5804 flags |= MGMT_ADV_FLAG_TX_POWER;
5805
5806 return flags;
5807}
5808
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005809static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
5810 void *data, u16 data_len)
5811{
5812 struct mgmt_rp_read_adv_features *rp;
5813 size_t rp_len;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005814 int err;
Florian Grandel286e0c82015-06-18 03:16:38 +02005815 struct adv_info *adv_instance;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005816 u32 supported_flags;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005817 u8 *instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005818
5819 BT_DBG("%s", hdev->name);
5820
Arman Uguray089fa8c2015-03-25 18:53:45 -07005821 if (!lmp_le_capable(hdev))
5822 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5823 MGMT_STATUS_REJECTED);
5824
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005825 hci_dev_lock(hdev);
5826
Johan Hedberg02c04af2015-11-26 12:15:58 +02005827 rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005828 rp = kmalloc(rp_len, GFP_ATOMIC);
5829 if (!rp) {
5830 hci_dev_unlock(hdev);
5831 return -ENOMEM;
5832 }
5833
Arman Uguray089fa8c2015-03-25 18:53:45 -07005834 supported_flags = get_supported_adv_flags(hdev);
5835
5836 rp->supported_flags = cpu_to_le32(supported_flags);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07005837 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
5838 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Florian Grandeld2609b32015-06-18 03:16:34 +02005839 rp->max_instances = HCI_MAX_ADV_INSTANCES;
Johan Hedberg02c04af2015-11-26 12:15:58 +02005840 rp->num_instances = hdev->adv_instance_cnt;
Arman Uguray24b4f382015-03-23 15:57:12 -07005841
Johan Hedberg02c04af2015-11-26 12:15:58 +02005842 instance = rp->instance;
5843 list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
5844 *instance = adv_instance->instance;
5845 instance++;
Arman Uguray24b4f382015-03-23 15:57:12 -07005846 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07005847
5848 hci_dev_unlock(hdev);
5849
5850 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
5851 MGMT_STATUS_SUCCESS, rp, rp_len);
5852
5853 kfree(rp);
5854
5855 return err;
5856}
5857
Arman Uguray4117ed72015-03-23 15:57:14 -07005858static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
Arman Ugurayb44133f2015-03-25 18:53:41 -07005859 u8 len, bool is_adv_data)
Arman Uguray24b4f382015-03-23 15:57:12 -07005860{
Arman Uguray4117ed72015-03-23 15:57:14 -07005861 u8 max_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07005862 int i, cur_len;
Arman Ugurayb44133f2015-03-25 18:53:41 -07005863 bool flags_managed = false;
Arman Uguray5507e352015-03-25 18:53:44 -07005864 bool tx_power_managed = false;
Arman Uguray24b4f382015-03-23 15:57:12 -07005865
Marcel Holtmann31a32482015-11-19 16:16:42 +01005866 if (is_adv_data) {
5867 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
5868 MGMT_ADV_FLAG_LIMITED_DISCOV |
5869 MGMT_ADV_FLAG_MANAGED_FLAGS)) {
5870 flags_managed = true;
5871 max_len -= 3;
5872 }
Arman Uguray24b4f382015-03-23 15:57:12 -07005873
Marcel Holtmann31a32482015-11-19 16:16:42 +01005874 if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
5875 tx_power_managed = true;
5876 max_len -= 3;
5877 }
Arman Uguray5507e352015-03-25 18:53:44 -07005878 }
5879
Arman Uguray4117ed72015-03-23 15:57:14 -07005880 if (len > max_len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005881 return false;
5882
Arman Uguray4117ed72015-03-23 15:57:14 -07005883 /* Make sure that the data is correctly formatted. */
5884 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
5885 cur_len = data[i];
Arman Uguray24b4f382015-03-23 15:57:12 -07005886
Arman Ugurayb44133f2015-03-25 18:53:41 -07005887 if (flags_managed && data[i + 1] == EIR_FLAGS)
5888 return false;
5889
Arman Uguray5507e352015-03-25 18:53:44 -07005890 if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
5891 return false;
5892
Arman Uguray24b4f382015-03-23 15:57:12 -07005893 /* If the current field length would exceed the total data
5894 * length, then it's invalid.
5895 */
Arman Uguray4117ed72015-03-23 15:57:14 -07005896 if (i + cur_len >= len)
Arman Uguray24b4f382015-03-23 15:57:12 -07005897 return false;
5898 }
5899
5900 return true;
5901}
5902
Arman Uguray24b4f382015-03-23 15:57:12 -07005903static void add_advertising_complete(struct hci_dev *hdev, u8 status,
5904 u16 opcode)
5905{
5906 struct mgmt_pending_cmd *cmd;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005907 struct mgmt_cp_add_advertising *cp;
Arman Uguray24b4f382015-03-23 15:57:12 -07005908 struct mgmt_rp_add_advertising rp;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005909 struct adv_info *adv_instance, *n;
5910 u8 instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005911
5912 BT_DBG("status %d", status);
5913
5914 hci_dev_lock(hdev);
5915
5916 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
5917
Florian Grandelfffd38b2015-06-18 03:16:47 +02005918 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
5919 if (!adv_instance->pending)
5920 continue;
5921
5922 if (!status) {
5923 adv_instance->pending = false;
5924 continue;
5925 }
5926
5927 instance = adv_instance->instance;
5928
5929 if (hdev->cur_adv_instance == instance)
5930 cancel_adv_timeout(hdev);
5931
5932 hci_remove_adv_instance(hdev, instance);
Johan Hedbergf2252572015-11-18 12:49:20 +02005933 mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07005934 }
5935
5936 if (!cmd)
5937 goto unlock;
5938
Florian Grandelfffd38b2015-06-18 03:16:47 +02005939 cp = cmd->param;
5940 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005941
5942 if (status)
5943 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5944 mgmt_status(status));
5945 else
5946 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
5947 mgmt_status(status), &rp, sizeof(rp));
5948
5949 mgmt_pending_remove(cmd);
5950
5951unlock:
5952 hci_dev_unlock(hdev);
5953}
5954
5955static int add_advertising(struct sock *sk, struct hci_dev *hdev,
5956 void *data, u16 data_len)
5957{
5958 struct mgmt_cp_add_advertising *cp = data;
5959 struct mgmt_rp_add_advertising rp;
5960 u32 flags;
Arman Uguray089fa8c2015-03-25 18:53:45 -07005961 u32 supported_flags;
Arman Uguray24b4f382015-03-23 15:57:12 -07005962 u8 status;
Florian Grandelfffd38b2015-06-18 03:16:47 +02005963 u16 timeout, duration;
5964 unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
5965 u8 schedule_instance = 0;
5966 struct adv_info *next_instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07005967 int err;
5968 struct mgmt_pending_cmd *cmd;
5969 struct hci_request req;
5970
5971 BT_DBG("%s", hdev->name);
5972
5973 status = mgmt_le_support(hdev);
5974 if (status)
5975 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5976 status);
5977
Marcel Holtmannceff86a2015-11-19 16:16:41 +01005978 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
5979 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5980 MGMT_STATUS_INVALID_PARAMS);
5981
Arman Uguray24b4f382015-03-23 15:57:12 -07005982 flags = __le32_to_cpu(cp->flags);
Arman Uguray912098a2015-03-23 15:57:15 -07005983 timeout = __le16_to_cpu(cp->timeout);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005984 duration = __le16_to_cpu(cp->duration);
Arman Uguray24b4f382015-03-23 15:57:12 -07005985
Florian Grandelfffd38b2015-06-18 03:16:47 +02005986 /* The current implementation only supports a subset of the specified
5987 * flags.
Arman Uguray089fa8c2015-03-25 18:53:45 -07005988 */
5989 supported_flags = get_supported_adv_flags(hdev);
Florian Grandelfffd38b2015-06-18 03:16:47 +02005990 if (flags & ~supported_flags)
Arman Uguray24b4f382015-03-23 15:57:12 -07005991 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5992 MGMT_STATUS_INVALID_PARAMS);
5993
5994 hci_dev_lock(hdev);
5995
Arman Uguray912098a2015-03-23 15:57:15 -07005996 if (timeout && !hdev_is_powered(hdev)) {
5997 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
5998 MGMT_STATUS_REJECTED);
5999 goto unlock;
6000 }
6001
Arman Uguray24b4f382015-03-23 15:57:12 -07006002 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006003 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006004 pending_find(MGMT_OP_SET_LE, hdev)) {
6005 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6006 MGMT_STATUS_BUSY);
6007 goto unlock;
6008 }
6009
Arman Ugurayb44133f2015-03-25 18:53:41 -07006010 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
Arman Uguray4117ed72015-03-23 15:57:14 -07006011 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
Arman Ugurayb44133f2015-03-25 18:53:41 -07006012 cp->scan_rsp_len, false)) {
Arman Uguray24b4f382015-03-23 15:57:12 -07006013 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6014 MGMT_STATUS_INVALID_PARAMS);
6015 goto unlock;
6016 }
6017
Florian Grandelfffd38b2015-06-18 03:16:47 +02006018 err = hci_add_adv_instance(hdev, cp->instance, flags,
6019 cp->adv_data_len, cp->data,
6020 cp->scan_rsp_len,
6021 cp->data + cp->adv_data_len,
6022 timeout, duration);
6023 if (err < 0) {
6024 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6025 MGMT_STATUS_FAILED);
6026 goto unlock;
6027 }
Arman Uguray24b4f382015-03-23 15:57:12 -07006028
Florian Grandelfffd38b2015-06-18 03:16:47 +02006029 /* Only trigger an advertising added event if a new instance was
6030 * actually added.
6031 */
6032 if (hdev->adv_instance_cnt > prev_instance_cnt)
Johan Hedbergf2252572015-11-18 12:49:20 +02006033 mgmt_advertising_added(sk, hdev, cp->instance);
Arman Uguray24b4f382015-03-23 15:57:12 -07006034
Florian Grandelfffd38b2015-06-18 03:16:47 +02006035 if (hdev->cur_adv_instance == cp->instance) {
6036 /* If the currently advertised instance is being changed then
6037 * cancel the current advertising and schedule the next
6038 * instance. If there is only one instance then the overridden
6039 * advertising data will be visible right away.
6040 */
6041 cancel_adv_timeout(hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006042
Florian Grandelfffd38b2015-06-18 03:16:47 +02006043 next_instance = hci_get_next_instance(hdev, cp->instance);
6044 if (next_instance)
6045 schedule_instance = next_instance->instance;
6046 } else if (!hdev->adv_instance_timeout) {
6047 /* Immediately advertise the new instance if no other
6048 * instance is currently being advertised.
6049 */
6050 schedule_instance = cp->instance;
6051 }
Arman Uguray912098a2015-03-23 15:57:15 -07006052
Florian Grandelfffd38b2015-06-18 03:16:47 +02006053 /* If the HCI_ADVERTISING flag is set or the device isn't powered or
6054 * there is no instance to be advertised then we have no HCI
6055 * communication to make. Simply return.
Arman Uguray24b4f382015-03-23 15:57:12 -07006056 */
6057 if (!hdev_is_powered(hdev) ||
Florian Grandelfffd38b2015-06-18 03:16:47 +02006058 hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6059 !schedule_instance) {
6060 rp.instance = cp->instance;
Arman Uguray24b4f382015-03-23 15:57:12 -07006061 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6062 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6063 goto unlock;
6064 }
6065
6066 /* We're good to go, update advertising data, parameters, and start
6067 * advertising.
6068 */
6069 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6070 data_len);
6071 if (!cmd) {
6072 err = -ENOMEM;
6073 goto unlock;
6074 }
6075
6076 hci_req_init(&req, hdev);
6077
Johan Hedbergf2252572015-11-18 12:49:20 +02006078 err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
Arman Uguray24b4f382015-03-23 15:57:12 -07006079
Florian Grandelfffd38b2015-06-18 03:16:47 +02006080 if (!err)
6081 err = hci_req_run(&req, add_advertising_complete);
6082
Arman Uguray24b4f382015-03-23 15:57:12 -07006083 if (err < 0)
6084 mgmt_pending_remove(cmd);
6085
6086unlock:
6087 hci_dev_unlock(hdev);
6088
6089 return err;
6090}
6091
Arman Ugurayda9293352015-03-23 15:57:13 -07006092static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6093 u16 opcode)
6094{
6095 struct mgmt_pending_cmd *cmd;
Florian Grandel01948332015-06-18 03:16:48 +02006096 struct mgmt_cp_remove_advertising *cp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006097 struct mgmt_rp_remove_advertising rp;
6098
6099 BT_DBG("status %d", status);
6100
6101 hci_dev_lock(hdev);
6102
6103 /* A failure status here only means that we failed to disable
6104 * advertising. Otherwise, the advertising instance has been removed,
6105 * so report success.
6106 */
6107 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6108 if (!cmd)
6109 goto unlock;
6110
Florian Grandel01948332015-06-18 03:16:48 +02006111 cp = cmd->param;
6112 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006113
6114 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6115 &rp, sizeof(rp));
6116 mgmt_pending_remove(cmd);
6117
6118unlock:
6119 hci_dev_unlock(hdev);
6120}
6121
6122static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6123 void *data, u16 data_len)
6124{
6125 struct mgmt_cp_remove_advertising *cp = data;
6126 struct mgmt_rp_remove_advertising rp;
Arman Ugurayda9293352015-03-23 15:57:13 -07006127 struct mgmt_pending_cmd *cmd;
6128 struct hci_request req;
Johan Hedberg952497b2015-06-18 21:05:31 +03006129 int err;
Arman Ugurayda9293352015-03-23 15:57:13 -07006130
6131 BT_DBG("%s", hdev->name);
6132
Arman Ugurayda9293352015-03-23 15:57:13 -07006133 hci_dev_lock(hdev);
6134
Johan Hedberg952497b2015-06-18 21:05:31 +03006135 if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
Florian Grandel01948332015-06-18 03:16:48 +02006136 err = mgmt_cmd_status(sk, hdev->id,
6137 MGMT_OP_REMOVE_ADVERTISING,
6138 MGMT_STATUS_INVALID_PARAMS);
6139 goto unlock;
6140 }
6141
Arman Ugurayda9293352015-03-23 15:57:13 -07006142 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6143 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6144 pending_find(MGMT_OP_SET_LE, hdev)) {
6145 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6146 MGMT_STATUS_BUSY);
6147 goto unlock;
6148 }
6149
Johan Hedberg17fd08f2015-11-26 12:15:59 +02006150 if (list_empty(&hdev->adv_instances)) {
Arman Ugurayda9293352015-03-23 15:57:13 -07006151 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6152 MGMT_STATUS_INVALID_PARAMS);
6153 goto unlock;
6154 }
6155
Florian Grandel01948332015-06-18 03:16:48 +02006156 hci_req_init(&req, hdev);
Arman Uguray912098a2015-03-23 15:57:15 -07006157
Johan Hedbergf2252572015-11-18 12:49:20 +02006158 hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
Arman Ugurayda9293352015-03-23 15:57:13 -07006159
Florian Grandel01948332015-06-18 03:16:48 +02006160 if (list_empty(&hdev->adv_instances))
Johan Hedbergf2252572015-11-18 12:49:20 +02006161 __hci_req_disable_advertising(&req);
Arman Ugurayda9293352015-03-23 15:57:13 -07006162
Florian Grandel01948332015-06-18 03:16:48 +02006163 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
6164 * flag is set or the device isn't powered then we have no HCI
6165 * communication to make. Simply return.
Arman Ugurayda9293352015-03-23 15:57:13 -07006166 */
Florian Grandel01948332015-06-18 03:16:48 +02006167 if (skb_queue_empty(&req.cmd_q) ||
6168 !hdev_is_powered(hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006169 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Florian Grandel01948332015-06-18 03:16:48 +02006170 rp.instance = cp->instance;
Arman Ugurayda9293352015-03-23 15:57:13 -07006171 err = mgmt_cmd_complete(sk, hdev->id,
6172 MGMT_OP_REMOVE_ADVERTISING,
6173 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6174 goto unlock;
6175 }
6176
6177 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6178 data_len);
6179 if (!cmd) {
6180 err = -ENOMEM;
6181 goto unlock;
6182 }
6183
Arman Ugurayda9293352015-03-23 15:57:13 -07006184 err = hci_req_run(&req, remove_advertising_complete);
6185 if (err < 0)
6186 mgmt_pending_remove(cmd);
6187
6188unlock:
6189 hci_dev_unlock(hdev);
6190
6191 return err;
6192}
6193
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006194static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
6195{
6196 u8 max_len = HCI_MAX_AD_LENGTH;
6197
6198 if (is_adv_data) {
6199 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
6200 MGMT_ADV_FLAG_LIMITED_DISCOV |
6201 MGMT_ADV_FLAG_MANAGED_FLAGS))
6202 max_len -= 3;
6203
6204 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
6205 max_len -= 3;
6206 }
6207
6208 return max_len;
6209}
6210
6211static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
6212 void *data, u16 data_len)
6213{
6214 struct mgmt_cp_get_adv_size_info *cp = data;
6215 struct mgmt_rp_get_adv_size_info rp;
6216 u32 flags, supported_flags;
6217 int err;
6218
6219 BT_DBG("%s", hdev->name);
6220
6221 if (!lmp_le_capable(hdev))
6222 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6223 MGMT_STATUS_REJECTED);
6224
6225 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
6226 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6227 MGMT_STATUS_INVALID_PARAMS);
6228
6229 flags = __le32_to_cpu(cp->flags);
6230
6231 /* The current implementation only supports a subset of the specified
6232 * flags.
6233 */
6234 supported_flags = get_supported_adv_flags(hdev);
6235 if (flags & ~supported_flags)
6236 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6237 MGMT_STATUS_INVALID_PARAMS);
6238
6239 rp.instance = cp->instance;
6240 rp.flags = cp->flags;
6241 rp.max_adv_data_len = tlv_data_max_len(flags, true);
6242 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
6243
6244 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
6245 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6246
6247 return err;
6248}
6249
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006250static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006251 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006252 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006253 HCI_MGMT_NO_HDEV |
6254 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006255 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006256 HCI_MGMT_NO_HDEV |
6257 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006258 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006259 HCI_MGMT_NO_HDEV |
6260 HCI_MGMT_UNTRUSTED },
6261 { read_controller_info, MGMT_READ_INFO_SIZE,
6262 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006263 { set_powered, MGMT_SETTING_SIZE },
6264 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6265 { set_connectable, MGMT_SETTING_SIZE },
6266 { set_fast_connectable, MGMT_SETTING_SIZE },
6267 { set_bondable, MGMT_SETTING_SIZE },
6268 { set_link_security, MGMT_SETTING_SIZE },
6269 { set_ssp, MGMT_SETTING_SIZE },
6270 { set_hs, MGMT_SETTING_SIZE },
6271 { set_le, MGMT_SETTING_SIZE },
6272 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6273 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6274 { add_uuid, MGMT_ADD_UUID_SIZE },
6275 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006276 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6277 HCI_MGMT_VAR_LEN },
6278 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6279 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006280 { disconnect, MGMT_DISCONNECT_SIZE },
6281 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6282 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6283 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6284 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6285 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6286 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6287 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6288 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6289 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6290 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6291 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006292 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6293 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6294 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006295 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6296 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6297 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6298 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6299 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6300 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6301 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6302 { set_advertising, MGMT_SETTING_SIZE },
6303 { set_bredr, MGMT_SETTING_SIZE },
6304 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6305 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6306 { set_secure_conn, MGMT_SETTING_SIZE },
6307 { set_debug_keys, MGMT_SETTING_SIZE },
6308 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006309 { load_irks, MGMT_LOAD_IRKS_SIZE,
6310 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006311 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6312 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6313 { add_device, MGMT_ADD_DEVICE_SIZE },
6314 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006315 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6316 HCI_MGMT_VAR_LEN },
6317 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006318 HCI_MGMT_NO_HDEV |
6319 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006320 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006321 HCI_MGMT_UNCONFIGURED |
6322 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006323 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6324 HCI_MGMT_UNCONFIGURED },
6325 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6326 HCI_MGMT_UNCONFIGURED },
6327 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6328 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006329 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006330 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006331 HCI_MGMT_NO_HDEV |
6332 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006333 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006334 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6335 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006336 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Marcel Holtmann40b25fe2015-11-19 16:16:43 +01006337 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
Johan Hedberg78b781c2016-01-05 13:19:32 +02006338 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006339};
6340
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006341void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006342{
Marcel Holtmannced85542015-03-14 19:27:56 -07006343 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006344
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006345 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6346 return;
6347
Marcel Holtmannf9207332015-03-14 19:27:55 -07006348 switch (hdev->dev_type) {
6349 case HCI_BREDR:
6350 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6351 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6352 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006353 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006354 } else {
6355 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6356 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006357 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006358 }
6359 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006360 case HCI_AMP:
6361 ev.type = 0x02;
6362 break;
6363 default:
6364 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006365 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006366
6367 ev.bus = hdev->bus;
6368
6369 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6370 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006371}
6372
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006373void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006374{
Marcel Holtmannced85542015-03-14 19:27:56 -07006375 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006376 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006377
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006378 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6379 return;
6380
Marcel Holtmannf9207332015-03-14 19:27:55 -07006381 switch (hdev->dev_type) {
6382 case HCI_BREDR:
6383 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006384
Marcel Holtmannf9207332015-03-14 19:27:55 -07006385 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6386 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6387 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006388 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006389 } else {
6390 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6391 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006392 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006393 }
6394 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006395 case HCI_AMP:
6396 ev.type = 0x02;
6397 break;
6398 default:
6399 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006400 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006401
6402 ev.bus = hdev->bus;
6403
6404 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6405 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006406}
6407
Andre Guedes6046dc32014-02-26 20:21:51 -03006408/* This function requires the caller holds hdev->lock */
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006409static void restart_le_actions(struct hci_dev *hdev)
Andre Guedes6046dc32014-02-26 20:21:51 -03006410{
6411 struct hci_conn_params *p;
6412
6413 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006414 /* Needed for AUTO_OFF case where might not "really"
6415 * have been powered off.
6416 */
6417 list_del_init(&p->action);
6418
6419 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006420 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006421 case HCI_AUTO_CONN_ALWAYS:
6422 list_add(&p->action, &hdev->pend_le_conns);
6423 break;
6424 case HCI_AUTO_CONN_REPORT:
6425 list_add(&p->action, &hdev->pend_le_reports);
6426 break;
6427 default:
6428 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006429 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006430 }
6431}
6432
Johan Hedberg2ff13892015-11-25 16:15:44 +02006433void mgmt_power_on(struct hci_dev *hdev, int err)
Johan Hedberg229ab392013-03-15 17:06:53 -05006434{
6435 struct cmd_lookup match = { NULL, hdev };
6436
Johan Hedberg2ff13892015-11-25 16:15:44 +02006437 BT_DBG("err %d", err);
Johan Hedberg229ab392013-03-15 17:06:53 -05006438
Johan Hedberg2ff13892015-11-25 16:15:44 +02006439 hci_dev_lock(hdev);
6440
6441 if (!err) {
Johan Hedbergaf02dd42015-11-11 08:11:21 +02006442 restart_le_actions(hdev);
6443 hci_update_background_scan(hdev);
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006444 }
6445
Johan Hedberg229ab392013-03-15 17:06:53 -05006446 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6447
6448 new_settings(hdev, match.sk);
6449
Johan Hedberg229ab392013-03-15 17:06:53 -05006450 if (match.sk)
6451 sock_put(match.sk);
Johan Hedberg2ff13892015-11-25 16:15:44 +02006452
6453 hci_dev_unlock(hdev);
Johan Hedberg229ab392013-03-15 17:06:53 -05006454}
6455
Johan Hedberg2ff13892015-11-25 16:15:44 +02006456void __mgmt_power_off(struct hci_dev *hdev)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006457{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006458 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006459 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedbergb24752f2011-11-03 14:40:33 +02006460
Johan Hedberg229ab392013-03-15 17:06:53 -05006461 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006462
6463 /* If the power off is because of hdev unregistration let
6464 * use the appropriate INVALID_INDEX status. Otherwise use
6465 * NOT_POWERED. We cover both scenarios here since later in
6466 * mgmt_index_removed() any hci_conn callbacks will have already
6467 * been triggered, potentially causing misleading DISCONNECTED
6468 * status responses.
6469 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006470 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006471 status = MGMT_STATUS_INVALID_INDEX;
6472 else
6473 status = MGMT_STATUS_NOT_POWERED;
6474
6475 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006476
6477 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006478 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6479 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006480
Johan Hedberg2ff13892015-11-25 16:15:44 +02006481 new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006482
6483 if (match.sk)
6484 sock_put(match.sk);
Johan Hedberg5add6af2010-12-16 10:00:37 +02006485}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006486
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006487void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006488{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006489 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006490 u8 status;
6491
Johan Hedberg333ae952015-03-17 13:48:47 +02006492 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006493 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006494 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006495
6496 if (err == -ERFKILL)
6497 status = MGMT_STATUS_RFKILLED;
6498 else
6499 status = MGMT_STATUS_FAILED;
6500
Johan Hedberga69e8372015-03-06 21:08:53 +02006501 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006502
6503 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006504}
6505
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006506void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6507 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006508{
Johan Hedberg86742e12011-11-07 23:13:38 +02006509 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006510
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006511 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006512
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006513 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006514 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006515 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006516 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006517 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006518 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006519
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006520 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006521}
Johan Hedbergf7520542011-01-20 12:34:39 +02006522
Johan Hedbergd7b25452014-05-23 13:19:53 +03006523static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6524{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006525 switch (ltk->type) {
6526 case SMP_LTK:
6527 case SMP_LTK_SLAVE:
6528 if (ltk->authenticated)
6529 return MGMT_LTK_AUTHENTICATED;
6530 return MGMT_LTK_UNAUTHENTICATED;
6531 case SMP_LTK_P256:
6532 if (ltk->authenticated)
6533 return MGMT_LTK_P256_AUTH;
6534 return MGMT_LTK_P256_UNAUTH;
6535 case SMP_LTK_P256_DEBUG:
6536 return MGMT_LTK_P256_DEBUG;
6537 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006538
6539 return MGMT_LTK_UNAUTHENTICATED;
6540}
6541
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006542void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006543{
6544 struct mgmt_ev_new_long_term_key ev;
6545
6546 memset(&ev, 0, sizeof(ev));
6547
Marcel Holtmann5192d302014-02-19 17:11:58 -08006548 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006549 * without providing an identity resolving key don't require
Marcel Holtmann5192d302014-02-19 17:11:58 -08006550 * to store long term keys. Their addresses will change the
6551 * next time around.
6552 *
6553 * Only when a remote device provides an identity address
6554 * make sure the long term key is stored. If the remote
6555 * identity is known, the long term keys are internally
6556 * mapped to the identity address. So allow static random
6557 * and public addresses here.
6558 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006559 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6560 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6561 ev.store_hint = 0x00;
6562 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006563 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006564
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006565 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006566 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006567 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006568 ev.key.enc_size = key->enc_size;
6569 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006570 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006571
Johan Hedberg2ceba532014-06-16 19:25:16 +03006572 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006573 ev.key.master = 1;
6574
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006575 /* Make sure we copy only the significant bytes based on the
6576 * encryption key size, and set the rest of the value to zeroes.
6577 */
Jakub Pawlowskicb922052015-08-05 23:16:29 +02006578 memcpy(ev.key.val, key->val, key->enc_size);
Johan Hedberg1fc62c52015-06-10 11:11:20 +03006579 memset(ev.key.val + key->enc_size, 0,
6580 sizeof(ev.key.val) - key->enc_size);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006581
Marcel Holtmann083368f2013-10-15 14:26:29 -07006582 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006583}
6584
Johan Hedbergcad20c22015-10-12 13:36:19 +02006585void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
Johan Hedberg95fbac82014-02-19 15:18:31 +02006586{
6587 struct mgmt_ev_new_irk ev;
6588
6589 memset(&ev, 0, sizeof(ev));
6590
Johan Hedbergcad20c22015-10-12 13:36:19 +02006591 ev.store_hint = persistent;
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006592
Johan Hedberg95fbac82014-02-19 15:18:31 +02006593 bacpy(&ev.rpa, &irk->rpa);
6594 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6595 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6596 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6597
6598 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6599}
6600
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006601void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6602 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006603{
6604 struct mgmt_ev_new_csrk ev;
6605
6606 memset(&ev, 0, sizeof(ev));
6607
6608 /* Devices using resolvable or non-resolvable random addresses
Florian Grandelf72186d2015-05-26 03:31:09 +02006609 * without providing an identity resolving key don't require
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006610 * to store signature resolving keys. Their addresses will change
6611 * the next time around.
6612 *
6613 * Only when a remote device provides an identity address
6614 * make sure the signature resolving key is stored. So allow
6615 * static random and public addresses here.
6616 */
6617 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6618 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6619 ev.store_hint = 0x00;
6620 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006621 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006622
6623 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6624 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006625 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006626 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6627
6628 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6629}
6630
Andre Guedesffb5a8272014-07-01 18:10:11 -03006631void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006632 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6633 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006634{
6635 struct mgmt_ev_new_conn_param ev;
6636
Johan Hedbergc103aea2014-07-02 17:37:34 +03006637 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6638 return;
6639
Andre Guedesffb5a8272014-07-01 18:10:11 -03006640 memset(&ev, 0, sizeof(ev));
6641 bacpy(&ev.addr.bdaddr, bdaddr);
6642 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006643 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006644 ev.min_interval = cpu_to_le16(min_interval);
6645 ev.max_interval = cpu_to_le16(max_interval);
6646 ev.latency = cpu_to_le16(latency);
6647 ev.timeout = cpu_to_le16(timeout);
6648
6649 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6650}
6651
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006652void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6653 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006654{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006655 char buf[512];
6656 struct mgmt_ev_device_connected *ev = (void *) buf;
6657 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006658
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006659 bacpy(&ev->addr.bdaddr, &conn->dst);
6660 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006661
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006662 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006663
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006664 /* We must ensure that the EIR Data fields are ordered and
6665 * unique. Keep it simple for now and avoid the problem by not
6666 * adding any BR/EDR data to the LE adv.
6667 */
6668 if (conn->le_adv_data_len > 0) {
6669 memcpy(&ev->eir[eir_len],
6670 conn->le_adv_data, conn->le_adv_data_len);
6671 eir_len = conn->le_adv_data_len;
6672 } else {
6673 if (name_len > 0)
6674 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6675 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006676
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006677 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006678 eir_len = eir_append_data(ev->eir, eir_len,
6679 EIR_CLASS_OF_DEV,
6680 conn->dev_class, 3);
6681 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006682
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006683 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006684
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006685 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6686 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006687}
6688
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006689static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006690{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006691 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006692
Johan Hedbergf5818c22014-12-05 13:36:02 +02006693 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006694
6695 *sk = cmd->sk;
6696 sock_hold(*sk);
6697
Johan Hedberga664b5b2011-02-19 12:06:02 -03006698 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006699}
6700
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006701static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006702{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006703 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006704 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006705
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006706 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6707
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006708 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006709 mgmt_pending_remove(cmd);
6710}
6711
Johan Hedberg84c61d92014-08-01 11:13:30 +03006712bool mgmt_powering_down(struct hci_dev *hdev)
6713{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006714 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006715 struct mgmt_mode *cp;
6716
Johan Hedberg333ae952015-03-17 13:48:47 +02006717 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03006718 if (!cmd)
6719 return false;
6720
6721 cp = cmd->param;
6722 if (!cp->val)
6723 return true;
6724
6725 return false;
6726}
6727
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006728void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006729 u8 link_type, u8 addr_type, u8 reason,
6730 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006731{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006732 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006733 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006734
Johan Hedberg84c61d92014-08-01 11:13:30 +03006735 /* The connection is still in hci_conn_hash so test for 1
6736 * instead of 0 to know if this is the last one.
6737 */
6738 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6739 cancel_delayed_work(&hdev->power_off);
6740 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006741 }
6742
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006743 if (!mgmt_connected)
6744 return;
6745
Andre Guedes57eb7762013-10-30 19:01:41 -03006746 if (link_type != ACL_LINK && link_type != LE_LINK)
6747 return;
6748
Johan Hedberg744cf192011-11-08 20:40:14 +02006749 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006750
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006751 bacpy(&ev.addr.bdaddr, bdaddr);
6752 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6753 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006754
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006755 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006756
6757 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006758 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006759
Johan Hedberg124f6e32012-02-09 13:50:12 +02006760 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006761 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006762}
6763
Marcel Holtmann78929242013-10-06 23:55:47 -07006764void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6765 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006766{
Andre Guedes3655bba2013-10-30 19:01:40 -03006767 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6768 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006769 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006770
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006771 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6772 hdev);
6773
Johan Hedberg333ae952015-03-17 13:48:47 +02006774 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006775 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006776 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006777
Andre Guedes3655bba2013-10-30 19:01:40 -03006778 cp = cmd->param;
6779
6780 if (bacmp(bdaddr, &cp->addr.bdaddr))
6781 return;
6782
6783 if (cp->addr.type != bdaddr_type)
6784 return;
6785
Johan Hedbergf5818c22014-12-05 13:36:02 +02006786 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006787 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006788}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006789
Marcel Holtmann445608d2013-10-06 23:55:48 -07006790void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6791 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006792{
6793 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006794
Johan Hedberg84c61d92014-08-01 11:13:30 +03006795 /* The connection is still in hci_conn_hash so test for 1
6796 * instead of 0 to know if this is the last one.
6797 */
6798 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6799 cancel_delayed_work(&hdev->power_off);
6800 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006801 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006802
Johan Hedberg4c659c32011-11-07 23:13:39 +02006803 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006804 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006805 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006806
Marcel Holtmann445608d2013-10-06 23:55:48 -07006807 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006808}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006809
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006810void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006811{
6812 struct mgmt_ev_pin_code_request ev;
6813
Johan Hedbergd8457692012-02-17 14:24:57 +02006814 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006815 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006816 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006817
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006818 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006819}
6820
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006821void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6822 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006823{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006824 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006825
Johan Hedberg333ae952015-03-17 13:48:47 +02006826 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006827 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006828 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006829
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006830 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006831 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006832}
6833
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006834void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6835 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006836{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006837 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006838
Johan Hedberg333ae952015-03-17 13:48:47 +02006839 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006840 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006841 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006842
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006843 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006844 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006845}
Johan Hedberga5c29682011-02-19 12:05:57 -03006846
Johan Hedberg744cf192011-11-08 20:40:14 +02006847int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006848 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006849 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006850{
6851 struct mgmt_ev_user_confirm_request ev;
6852
Johan Hedberg744cf192011-11-08 20:40:14 +02006853 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006854
Johan Hedberg272d90d2012-02-09 15:26:12 +02006855 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006856 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006857 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006858 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006859
Johan Hedberg744cf192011-11-08 20:40:14 +02006860 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006861 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006862}
6863
Johan Hedberg272d90d2012-02-09 15:26:12 +02006864int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006865 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08006866{
6867 struct mgmt_ev_user_passkey_request ev;
6868
6869 BT_DBG("%s", hdev->name);
6870
Johan Hedberg272d90d2012-02-09 15:26:12 +02006871 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006872 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08006873
6874 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006875 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08006876}
6877
Brian Gix0df4c182011-11-16 13:53:13 -08006878static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006879 u8 link_type, u8 addr_type, u8 status,
6880 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03006881{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006882 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03006883
Johan Hedberg333ae952015-03-17 13:48:47 +02006884 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03006885 if (!cmd)
6886 return -ENOENT;
6887
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006888 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006889 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03006890
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006891 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03006892}
6893
Johan Hedberg744cf192011-11-08 20:40:14 +02006894int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006895 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006896{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006897 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006898 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006899}
6900
Johan Hedberg272d90d2012-02-09 15:26:12 +02006901int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006902 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03006903{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006904 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006905 status,
6906 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03006907}
Johan Hedberg2a611692011-02-19 12:06:00 -03006908
Brian Gix604086b2011-11-23 08:28:33 -08006909int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006910 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006911{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006912 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006913 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006914}
6915
Johan Hedberg272d90d2012-02-09 15:26:12 +02006916int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006917 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08006918{
Johan Hedberg272d90d2012-02-09 15:26:12 +02006919 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03006920 status,
6921 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08006922}
6923
Johan Hedberg92a25252012-09-06 18:39:26 +03006924int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
6925 u8 link_type, u8 addr_type, u32 passkey,
6926 u8 entered)
6927{
6928 struct mgmt_ev_passkey_notify ev;
6929
6930 BT_DBG("%s", hdev->name);
6931
6932 bacpy(&ev.addr.bdaddr, bdaddr);
6933 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6934 ev.passkey = __cpu_to_le32(passkey);
6935 ev.entered = entered;
6936
6937 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
6938}
6939
Johan Hedberge1e930f2014-09-08 17:09:49 -07006940void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03006941{
6942 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006943 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07006944 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03006945
Johan Hedberge1e930f2014-09-08 17:09:49 -07006946 bacpy(&ev.addr.bdaddr, &conn->dst);
6947 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
6948 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03006949
Johan Hedberge1e930f2014-09-08 17:09:49 -07006950 cmd = find_pairing(conn);
6951
6952 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
6953 cmd ? cmd->sk : NULL);
6954
Johan Hedberga511b352014-12-11 21:45:45 +02006955 if (cmd) {
6956 cmd->cmd_complete(cmd, status);
6957 mgmt_pending_remove(cmd);
6958 }
Johan Hedberg2a611692011-02-19 12:06:00 -03006959}
Johan Hedbergb312b1612011-03-16 14:29:37 +02006960
Marcel Holtmann464996a2013-10-15 14:26:24 -07006961void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006962{
6963 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07006964 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006965
6966 if (status) {
6967 u8 mgmt_err = mgmt_status(status);
6968 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006969 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07006970 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006971 }
6972
Marcel Holtmann464996a2013-10-15 14:26:24 -07006973 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07006974 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07006975 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006976 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02006977
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006978 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006979 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006980
Johan Hedberg47990ea2012-02-22 11:58:37 +02006981 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07006982 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006983
6984 if (match.sk)
6985 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02006986}
6987
Johan Hedberg890ea892013-03-15 17:06:52 -05006988static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02006989{
Johan Hedberg890ea892013-03-15 17:06:52 -05006990 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02006991 struct hci_cp_write_eir cp;
6992
Johan Hedberg976eb202012-10-24 21:12:01 +03006993 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006994 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02006995
Johan Hedbergc80da272012-02-22 15:38:48 +02006996 memset(hdev->eir, 0, sizeof(hdev->eir));
6997
Johan Hedbergcacaf522012-02-21 00:52:42 +02006998 memset(&cp, 0, sizeof(cp));
6999
Johan Hedberg890ea892013-03-15 17:06:52 -05007000 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007001}
7002
Marcel Holtmann3e248562013-10-15 14:26:25 -07007003void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007004{
7005 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007006 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007007 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007008
7009 if (status) {
7010 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007011
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007012 if (enable && hci_dev_test_and_clear_flag(hdev,
7013 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007014 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007015 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007016 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007017
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007018 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7019 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007020 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007021 }
7022
7023 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007024 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007025 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007026 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007027 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007028 changed = hci_dev_test_and_clear_flag(hdev,
7029 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007030 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007031 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007032 }
7033
7034 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7035
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007036 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007037 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007038
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007039 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007040 sock_put(match.sk);
7041
Johan Hedberg890ea892013-03-15 17:06:52 -05007042 hci_req_init(&req, hdev);
7043
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007044 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7045 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007046 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7047 sizeof(enable), &enable);
Johan Hedbergb1a89172015-11-25 16:15:42 +02007048 __hci_req_update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007049 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007050 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007051 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007052
7053 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007054}
7055
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007056static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007057{
7058 struct cmd_lookup *match = data;
7059
Johan Hedberg90e70452012-02-23 23:09:40 +02007060 if (match->sk == NULL) {
7061 match->sk = cmd->sk;
7062 sock_hold(match->sk);
7063 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007064}
7065
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007066void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7067 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007068{
Johan Hedberg90e70452012-02-23 23:09:40 +02007069 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007070
Johan Hedberg92da6092013-03-15 17:06:55 -05007071 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7072 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7073 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007074
7075 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007076 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7077 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007078
7079 if (match.sk)
7080 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007081}
7082
Marcel Holtmann7667da32013-10-15 14:26:27 -07007083void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007084{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007085 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007086 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007087
Johan Hedberg13928972013-03-15 17:07:00 -05007088 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007089 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007090
7091 memset(&ev, 0, sizeof(ev));
7092 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007093 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007094
Johan Hedberg333ae952015-03-17 13:48:47 +02007095 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007096 if (!cmd) {
7097 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007098
Johan Hedberg13928972013-03-15 17:07:00 -05007099 /* If this is a HCI command related to powering on the
7100 * HCI dev don't send any mgmt signals.
7101 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007102 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007103 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007104 }
7105
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007106 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7107 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007108}
Szymon Jancc35938b2011-03-22 13:12:21 +01007109
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007110static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7111{
7112 int i;
7113
7114 for (i = 0; i < uuid_count; i++) {
7115 if (!memcmp(uuid, uuids[i], 16))
7116 return true;
7117 }
7118
7119 return false;
7120}
7121
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007122static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7123{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007124 u16 parsed = 0;
7125
7126 while (parsed < eir_len) {
7127 u8 field_len = eir[0];
7128 u8 uuid[16];
7129 int i;
7130
7131 if (field_len == 0)
7132 break;
7133
7134 if (eir_len - parsed < field_len + 1)
7135 break;
7136
7137 switch (eir[1]) {
7138 case EIR_UUID16_ALL:
7139 case EIR_UUID16_SOME:
7140 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007141 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007142 uuid[13] = eir[i + 3];
7143 uuid[12] = eir[i + 2];
7144 if (has_uuid(uuid, uuid_count, uuids))
7145 return true;
7146 }
7147 break;
7148 case EIR_UUID32_ALL:
7149 case EIR_UUID32_SOME:
7150 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007151 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007152 uuid[15] = eir[i + 5];
7153 uuid[14] = eir[i + 4];
7154 uuid[13] = eir[i + 3];
7155 uuid[12] = eir[i + 2];
7156 if (has_uuid(uuid, uuid_count, uuids))
7157 return true;
7158 }
7159 break;
7160 case EIR_UUID128_ALL:
7161 case EIR_UUID128_SOME:
7162 for (i = 0; i + 17 <= field_len; i += 16) {
7163 memcpy(uuid, eir + i + 2, 16);
7164 if (has_uuid(uuid, uuid_count, uuids))
7165 return true;
7166 }
7167 break;
7168 }
7169
7170 parsed += field_len + 1;
7171 eir += field_len + 1;
7172 }
7173
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007174 return false;
7175}
7176
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007177static void restart_le_scan(struct hci_dev *hdev)
7178{
7179 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007180 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007181 return;
7182
7183 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7184 hdev->discovery.scan_start +
7185 hdev->discovery.scan_duration))
7186 return;
7187
Johan Hedberg7c1fbed2015-11-11 08:11:23 +02007188 queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007189 DISCOV_LE_RESTART_DELAY);
7190}
7191
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007192static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7193 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7194{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007195 /* If a RSSI threshold has been specified, and
7196 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7197 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7198 * is set, let it through for further processing, as we might need to
7199 * restart the scan.
7200 *
7201 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7202 * the results are also dropped.
7203 */
7204 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7205 (rssi == HCI_RSSI_INVALID ||
7206 (rssi < hdev->discovery.rssi &&
7207 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7208 return false;
7209
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007210 if (hdev->discovery.uuid_count != 0) {
7211 /* If a list of UUIDs is provided in filter, results with no
7212 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007213 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007214 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7215 hdev->discovery.uuids) &&
7216 !eir_has_uuids(scan_rsp, scan_rsp_len,
7217 hdev->discovery.uuid_count,
7218 hdev->discovery.uuids))
7219 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007220 }
7221
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007222 /* If duplicate filtering does not report RSSI changes, then restart
7223 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007224 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007225 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7226 restart_le_scan(hdev);
7227
7228 /* Validate RSSI value against the RSSI threshold once more. */
7229 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7230 rssi < hdev->discovery.rssi)
7231 return false;
7232 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007233
7234 return true;
7235}
7236
Marcel Holtmann901801b2013-10-06 23:55:51 -07007237void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007238 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7239 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007240{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007241 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007242 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007243 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007244
Johan Hedberg75ce2082014-07-02 22:42:01 +03007245 /* Don't send events for a non-kernel initiated discovery. With
7246 * LE one exception is if we have pend_le_reports > 0 in which
7247 * case we're doing passive scanning and want these events.
7248 */
7249 if (!hci_discovery_active(hdev)) {
7250 if (link_type == ACL_LINK)
7251 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007252 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007253 return;
7254 }
Andre Guedes12602d02013-04-30 15:29:40 -03007255
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007256 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007257 /* We are using service discovery */
7258 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7259 scan_rsp_len))
7260 return;
7261 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007262
Johan Hedberg78b781c2016-01-05 13:19:32 +02007263 if (hdev->discovery.limited) {
7264 /* Check for limited discoverable bit */
7265 if (dev_class) {
7266 if (!(dev_class[1] & 0x20))
7267 return;
7268 } else {
7269 u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);
7270 if (!flags || !(flags[0] & LE_AD_LIMITED))
7271 return;
7272 }
7273 }
7274
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007275 /* Make sure that the buffer is big enough. The 5 extra bytes
7276 * are for the potential CoD field.
7277 */
7278 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007279 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007280
Johan Hedberg1dc06092012-01-15 21:01:23 +02007281 memset(buf, 0, sizeof(buf));
7282
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007283 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7284 * RSSI value was reported as 0 when not available. This behavior
7285 * is kept when using device discovery. This is required for full
7286 * backwards compatibility with the API.
7287 *
7288 * However when using service discovery, the value 127 will be
7289 * returned when the RSSI is not available.
7290 */
Szymon Janc91200e92015-01-22 16:57:05 +01007291 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7292 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007293 rssi = 0;
7294
Johan Hedberg841c5642014-07-07 12:45:54 +03007295 bacpy(&ev->addr.bdaddr, bdaddr);
7296 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007297 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007298 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007299
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007300 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007301 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007302 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007303
Johan Hedberg0d3b7f62016-01-05 13:19:31 +02007304 if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
7305 NULL))
Johan Hedberg1dc06092012-01-15 21:01:23 +02007306 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007307 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007308
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007309 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007310 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007311 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007312
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007313 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7314 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007315
Marcel Holtmann901801b2013-10-06 23:55:51 -07007316 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007317}
Johan Hedberga88a9652011-03-30 13:18:12 +03007318
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007319void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7320 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007321{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007322 struct mgmt_ev_device_found *ev;
7323 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7324 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007325
Johan Hedbergb644ba32012-01-17 21:48:47 +02007326 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007327
Johan Hedbergb644ba32012-01-17 21:48:47 +02007328 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007329
Johan Hedbergb644ba32012-01-17 21:48:47 +02007330 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007331 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007332 ev->rssi = rssi;
7333
7334 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007335 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007336
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007337 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007338
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007339 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007340}
Johan Hedberg314b2382011-04-27 10:29:57 -04007341
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007342void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007343{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007344 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007345
Andre Guedes343fb142011-11-22 17:14:19 -03007346 BT_DBG("%s discovering %u", hdev->name, discovering);
7347
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007348 memset(&ev, 0, sizeof(ev));
7349 ev.type = hdev->discovery.type;
7350 ev.discovering = discovering;
7351
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007352 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007353}
Antti Julku5e762442011-08-25 16:48:02 +03007354
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007355static struct hci_mgmt_chan chan = {
7356 .channel = HCI_CHANNEL_CONTROL,
7357 .handler_count = ARRAY_SIZE(mgmt_handlers),
7358 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007359 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007360};
7361
7362int mgmt_init(void)
7363{
7364 return hci_mgmt_chan_register(&chan);
7365}
7366
7367void mgmt_exit(void)
7368{
7369 hci_mgmt_chan_unregister(&chan);
7370}